题意:有\(r\)X\(r\)的网格图,有\(n\)位名人,会在\(t_i\)时出现在\((x_i,y_i)\),如果过了\(t_i\)名人就会消失,从某一点走到另外一点需要花费的时间是它们之间的曼哈顿距离的值,你刚开始在\((1,1)\)点,问你最多能给多少名人拍照.
题解:因为某个点是从另外一个点走过来的,所以我们不难想到使用dp来解决此题,直接写线性dp的话时间复杂度是\(O(n^2)\),但是我们会发现,因为题目给的名人的出现时间\(t_i\)是递增的,而两个点的最大的曼哈顿距离是\(2*(r-1)\),所以我们第二层循环遍历到\(e[i].t-e[j].t>=2*(r-1)\)的时候,前面的\([1,j]\)的所有点都是满足条件的,而我们是从这些点走过来的,所以\([1,j]\)的最优情况已经求出来过了,而我们只需每次维护一个前缀的最大值(\(pre[i]\))就能\(O(1)\)求出\([1,j]\)的最优解,特别注意除了\(dp[1]\)以外的\(dp\)应初始化为\(-INF\),因为边界是\((1,1)\),其他点只能线性的从\((1,1)\)转移过来.
-
代码:
struct misaka{
int t;
int x,y;
}e[N]; int r,n;
int dp[N];
int pre[N]; int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>r>>n;
e[1].t=0,e[1].x=1,e[1].y=1;
for(int i=2;i<=n+1;++i) cin>>e[i].t>>e[i].x>>e[i].y; for(int i=2;i<=n+1;++i){
dp[i]=-INF;
for(int j=i-1;j>=1;--j){
if(e[i].t-e[j].t>=2*(r-1)){
dp[i]=max(dp[i],pre[j]+1);
break;
}
if(e[i].t-e[j].t>=abs(e[i].x-e[j].x)+abs(e[i].y-e[j].y)){
dp[i]=max(dp[i],dp[j]+1);
}
}
pre[i]=max(dp[i],pre[i-1]);
} cout<<pre[n+1]<<'\n'; return 0;
}