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\n",i,i,dp[i],el,er,maxs);
        que[++er] = i;
        ans = max(ans,dp[i]);
    }
    printf("%d\n",ans);
    return 0;
}
posted @ 2021-03-16 21:58  EchoZQN  阅读(53)  评论(0编辑  收藏  举报