codeforces 1427C - The Hard Work of Paparazzi (dp)

题目链接:https://codeforces.com/problemset/problem/1427/C

\(dp[i]\) 表示拍到第 \(i\) 个艺人的情况下,能拍到的最多次数
显然的 \(O(n^2)\) 转移是 :

\[dp[i] = max_{j = 0}^{i - 1}(dp[i-1] + 1) (t[i] - t[j] >= \mid x_i - x_j\mid + \mid y_i - y_j\mid) \]

但这也显然是不行的,注意到还有 \(r <= 500\) 的条件没有用到,
因为时间是单调递增的,所以第 \(i\) 个明星和第 \(j\) 个明星出现的时间最少相差 \(i - j\) 分钟,而如果 \(i - j >= 2 * (r - 1)\),
那从整张地图上的任意一个点,都可以在规定时间内到达第 \(i\) 个明星出现的位置,
所以维护一个 \(mx\) 数组,\(mx[i] = max_{j=0}^{i}(dp[i])\), 则只需要枚举第 \(i\) 个明星的前 \(2*(r-1)\) 个明星进行转移即可
时间复杂度就降低到了 \(O(nr)\)

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;

const int maxn = 100010;

int r, n;
int dp[maxn], mx[maxn];
int t[maxn], x[maxn], y[maxn];

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	r = read(), n = read();
	
	for(int i = 1 ; i <= n ; ++i){ 
		t[i] = read(), x[i] = read(), y[i] = read();
	}
	
	memset(dp, -1, sizeof(dp));
	x[0] = 1, y[0] = 1;
	dp[0] = 0;
	for(int i = 1 ; i <= n ; ++i){
		if(i >= 2 * (r - 1) + 1)dp[i] = max(dp[i], mx[i - 2 * (r - 1) - 1] + 1);
		for(int j = i - 1 ; j >= max(0, i - 2 * (r - 1)) ; --j){
			if(dp[j] >= 0 && t[i] - t[j] >= abs(x[i] - x[j]) + abs(y[i] - y[j])){ // dp[j] >= 0: 只能从合法的状态转移过来
				dp[i] = max(dp[i], dp[j] + 1);
			}
		}
		mx[i] = max(mx[i - 1], dp[i]);
	}
	
	int ans = 0;
	for(int i = 1 ; i <= n ; ++i) ans = max(ans, dp[i]);
	printf("%d\n", ans);
	
	return 0;
}
posted @ 2020-12-04 19:58  Tartarus_li  阅读(94)  评论(0编辑  收藏  举报