1. 程式人生 > 實用技巧 >CF1456D. Cakes for Clones

CF1456D. Cakes for Clones

題目大意

一個無限長的數軸,初始0時間人在位置0,接下來在ti時位置xi會出現一個蛋糕,必須要在ti瞬間瞬間接住否則失敗

人可以在任意時刻放分身,分身接蛋糕但不能動,至多同時存在一個分身,新放的會取代原來的

判斷是否能接完所有蛋糕

n<=5000,座標時間兩兩不同

題解

做法很多,但是想出一個陽間做法很難

我的想法:設f[i,j],g[i,j]表示第i個蛋糕落下來時,人接分身在j/分身接人在j,問題是有人放下分身後馬上趕路的情況,這樣可能在分身接住蛋糕時人不在下落點上

題解做法設f[i]表示接住了前i個蛋糕,且第i個蛋糕是用分身接(已接住或者已經放好了等著蛋糕下來)的最小時間,這樣就解決了上面的問題

再設g[i,j]表示接住了前i個蛋糕分身在蛋糕j處是否可行,且第i個蛋糕是用本體接的

轉移考慮分本體和分身接討論,先考慮f[i]:

①i+1用本體接:則可以找一個地方j放分身,然後從j跑到i+1更新g[i+1,j],注意放分身時接i的分身必須已接完

②i+1用分身接:直接往i+1跑更新f[i+1],也要注意要先接到i

接著考慮g[i,j],當i+1!=j時顯然只能用本體接i+1,當i+1=j時用分身接i+1,然後考慮i+2怎麼接:

①i+2用本體接:找一個地方k放分身,然後i->k->i+2更新g[i+2,k],注意在k處放分身時i+1要已接到

②i+2用分身接:直接i->i+2更新f[i+2],同樣i+1要接到

時間複雜度O(n^2)

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define abs(x) ((x)>0?(x):-(x))
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define ll long long
//#define file
using namespace std;

int n,i,j,k,l;
int t[5001],x[5001];
ll f[5001];
bool g[5001][5001];

int main()
{
	#ifdef file
	freopen("CF1456D.in","r",stdin);
	#endif
	
	scanf("%d",&n);
	fo(i,1,n) scanf("%d%d",&t[i],&x[i]);
	
	memset(f,1,sizeof(f));f[0]=0;
	fo(i,0,n-1)
	{
		if (f[i]<=t[i])
		{
			fo(j,i+2,n) if (max(f[i]+abs(x[i]-x[j]),t[i])+abs(x[j]-x[i+1])<=t[i+1]) g[i+1][j]=1;
			f[i+1]=min(f[i+1],max(f[i]+abs(x[i]-x[i+1]),t[i]));
		}
		fo(j,i+2,n) if (g[i][j] && t[i]+abs(x[i]-x[i+1])<=t[i+1]) g[i+1][j]=1;
		if (g[i][i+1])
		{
			if (i<n-1)
			{
				fo(k,i+3,n) if (max(t[i]+abs(x[i]-x[k]),t[i+1])+abs(x[k]-x[i+2])<=t[i+2]) g[i+2][k]=1;
				f[i+2]=min(f[i+2],max(t[i]+abs(x[i]-x[i+2]),t[i+1]));
			}
			else f[n]=0;
		}
	}
	printf((f[n]<=t[n])?"YES\n":"NO\n");
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}