C. The Hard Work of Paparazzi dp

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;
}
原文地址:https://www.cnblogs.com/EchoZQN/p/14546231.html