C. The Hard Work of Paparazzi dp
题目大意:
给你一个大小为 (r*r) 大小的矩阵,初始你在位置 ((1,1)) 这个点,有 (n) 个点,对于第 (i) 个人来说,它只在 (t_i) 时刻处于 ((x_i,y_i)) 这个位置,如果此时你也在这个位置,那么你就可以收获到这个点,如果你此时在 ((x,y)) 这个位置,那么经过 (t = abs(x-x_i)+abs(x-y_i)) 时间,你可以到达 ((x_i,y_i)) 这个位置,问你最多可以收获多少个点,保证 (t_i<t_{i+1}<=1000000) ,(1<=x_i,y_i<=r<=500) (n<=100000)
题解:
- 碰到 (dp) 这种题目,首先要找到一个合适的 (dp) 的定义
- (dp[i]) 表示在 (t_i) 时刻,位置 ((x_i,y_i)) 的最优解
- 因为保证 (t_i<t_{i+1}) ,注意是严格小于
- 所以对于每一个时刻最多只有一个点
- 那么,因为 (r<=500) ,所以如果时刻相差大于等于 (1000) 就一定可以转移
- 所以,我最多只需要枚举前面1000个时间点
- 复杂度是 (O(n*1000))
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+10;
typedef long long ll;
int dp[maxn],que[maxn],x[maxn],y[maxn],t[maxn];
/*
* dp[i] 表示在 ti 时刻,位置 (xi,yi) 的最优解
*/
int main(){
int r,n;
scanf("%d%d",&r,&n);
for(int i=1;i<=n;i++) scanf("%d%d%d",&t[i],&x[i],&y[i]);
memset(dp,0xef,sizeof(dp));
x[0] = y[0] = 1,dp[0] = 0,t[0] = 0;
int el = 1,er = 1,maxs = -1e9,ans = 0;
que[el] = 0;
for(int i=1;i<=n;i++){
while(el<=er&&t[i]-t[que[el]]>=1000) maxs = max(maxs,dp[que[el]]),el++;
dp[i] = max(dp[i],maxs+1);
for(int j=el;j<=er;j++){
int id = que[j],val = abs(x[i]-x[id])+abs(y[i]-y[id]);
if(t[i]-t[id]>=val) dp[i] = max(dp[i],dp[id]+1);
}
// printf("i = %d dp[%d]=%d el = %d er = %d maxs = %d
",i,i,dp[i],el,er,maxs);
que[++er] = i;
ans = max(ans,dp[i]);
}
printf("%d
",ans);
return 0;
}