CF1456 D. Cakes for Clones
在一个数轴上,在\(t_i\)时刻会掉下一个物品于\(x_i\)。你需要按时接住所有的物品。从\(0\)开始,每单位时间可以移动一单位距离。你可以在任意时刻放一个克隆,克隆可以接住恰好掉在它上面的物品,且克隆不能动。在放一个克隆的时候上一个克隆会消失。
问是否可以接住所有的物品。
\(t_i,x_i\)互不相同。
\(n\le 5000\)
比赛的时候想了个比较冗余的做法最终也没有写出来。
题解做法阳间多了:设\(g_i\)表示到达\(i\)且此时的克隆变得没用了的最小时间,\(f_{i,j}\)表示刚好按时走到\(i\)并且克隆在\(j\)是否可行。
\(g_i\)转移:1. 在\(i\)丢个克隆然后跑到\(i+1\),即\(g_{i+1}\)。2. 跑到\(j\)再跑到\(i+1\),即\(f_{i+1,j}\)。
\(f_{i,j}\)转移:
- \(j\neq i+1\)时,直接跑到\(i+1\),即\(f_{i+1,j}\)
- \(j=i+1\)时:(1) 跑到\(i+2\),即\(g_{i+2}\)。(2) 跑到\(k\)放克隆再跑到\(i+2\),即\(f_{i+2,k}\)。
可以发现这已经涵盖了最优的情况。
\(O(n^2)\)。
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 5005
int n;
int t[N],x[N];
bool f[N][N];
int g[N];
bool work(){
memset(g,127,sizeof g);
g[0]=0;
for (int i=0;i<n;++i){
if (g[i]<=t[i]){
g[i+1]=min(g[i+1],max(g[i]+abs(x[i]-x[i+1]),t[i]));
for (int j=i+2;j<=n;++j)
f[i+1][j]|=(max(g[i]+abs(x[i]-x[j]),t[i])+abs(x[j]-x[i+1])<=t[i+1]);
}
for (int j=i+2;j<=n;++j)
f[i+1][j]|=(f[i][j] && t[i]+abs(x[i]-x[i+1])<=t[i+1]);
if (f[i][i+1] && i+2<=n){
g[i+2]=min(g[i+2],max(t[i]+abs(x[i]-x[i+2]),t[i+1]));
for (int k=i+3;k<=n;++k)
f[i+2][k]|=(max(t[i]+abs(x[i]-x[k]),t[i+1])+abs(x[k]-x[i+2])<=t[i+2]);
}
}
return g[n]<=t[n] || f[n-1][n];
}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;++i)
scanf("%d%d",&t[i],&x[i]);
if (work())
printf("YES\n");
else
printf("NO\n");
return 0;
}