【题解】【Sue 的小球】

【题解】【Sue 的小球】

题目

题目分析

Sue每经过一个彩蛋必定把它拿下来(贪心),所以,在任意一个时刻下,Sue收集的彩蛋必定是一段连续的区间,因此,容易想到区间dp

容易想到设f[i][j][t][0/1]表示在前t个单位时间里,收集完i到j个彩蛋后,到达i或j的最大分数

转移方程:
f[i][j][t][0]=max{f[i+1][j][t-(x[i+1]-x[i])[0]+y[i]-t*v[i],f[i+1][j][t-(x[j]-x[i])[1]+y[i]-t*v[i]}
f[i][j][t][1]=max{f[i][j-1][t-(x[j]-x[i])[0]+y[j]-t*v[j],f[i][j-1][t-(x[j]-x[j-1])[1]+y[j]-t*v[j]}

但是发现N<=1000,而我们的状态是三维的,于是考虑简化状态
实际上题目中并没有要求收集完彩蛋的截止时间,而我们之所以设出时间这一维,只是为了在转移时便于计算当前彩蛋的高度
但是这个时间其实我们是可以提前计算的,因为每进行一次转移,我们都知道时间过去了多少,而所有目前还没有获得的彩蛋的高度都会因此而下降,总共下降的高度可以用前缀和*时间来计算
因此我们可以省略掉时间这一维,每进行一次转移,就将这次转移消耗的时间累计到答案中,这便是“费用提前计算”的策略

转移方程

f[i][j][0]=max{f[i+1][j][0]+y[i]-(sumv[i]+sumv[n]-sumv[j])*(x[i+1]-x[i]),f[i+1][j][1]+y[i]-(sumv[i]+sumv[n]-sumv[j])*(x[j]-x[i])}
f[i][j][1]=max{f[i][j-1][0]+y[j]-(sumv[i-1]+sumv[n]-sumv[j-1])*(x[j]-x[i]),f[i][j-1][1]+y[j]-(sumv[i-1]+sumv[n]-sumv[j-1])*(x[j]-x[j-1])}

PS:

从数学上可以理解为使用乘法分配律,将最初的三维方程中的t,分成了每次转移时的一段
需要注意的是这样的话中间状态的结果不能直接当答案输出,因为其累加了未来的费用,但是最终答案会是正确的

Code

#include<bits/stdc++.h>
#include<vector>
#include<queue>
using namespace std;
#define int long long
inline int read()
{
	register int x=0,w=1;
	register char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if(ch=='-'){ch=getchar();w=-1;}
	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*w;
}
const int INF=(1ll<<62); 
int n,s,f[1005][1005][2],sumv[1005],res[10];
struct node{
	int x,y,v;
	bool operator<(const node&z)const{
	return x<z.x;
	}
}egg[1005];
signed main()
{
    n=read();s=read();
    for(int i=1;i<=n;++i) egg[i].x=read();
    for(int i=1;i<=n;++i) egg[i].y=read();
    for(int i=1;i<=n;++i) egg[i].v=read();
    sort(egg+1,egg+n+1);
    for(int i=0;i<=n+1;++i)
      for(int j=i;j<=n+1;++j)
        f[i][j][0]=f[i][j][1]=-INF;
    for(int i=1;i<=n;++i)
      sumv[i]=sumv[i-1]+egg[i].v;
	egg[0].x=-INF;
	egg[n+1].x=INF;
	for(int i=0;i<=n;++i){
		if(s>=egg[i].x&&s<=egg[i+1].x){
			f[i][i][0]=f[i][i][1]=egg[i].y-sumv[n]*(s-egg[i].x);
			f[i+1][i+1][0]=f[i+1][i+1][1]=egg[i+1].y-sumv[n]*(egg[i+1].x-s);
			break;
		}
	}
	for(int len=2;len<=n;++len)
	{
		for(int i=1;i+len-1<=n;++i)
		{
			int j=i+len-1;
			f[i][j][0]=max(f[i+1][j][0]+egg[i].y-(sumv[i]+sumv[n]-sumv[j])*(egg[i+1].x-egg[i].x),f[i+1][j][1]+egg[i].y-(sumv[i]+sumv[n]-sumv[j])*(egg[j].x-egg[i].x));
			f[i][j][1]=max(f[i][j-1][0]+egg[j].y-(sumv[i-1]+sumv[n]-sumv[j-1])*(egg[j].x-egg[i].x),f[i][j-1][1]+egg[j].y-(sumv[i-1]+sumv[n]-sumv[j-1])*(egg[j].x-egg[j-1].x));
		}
	}
	int w=1;
	int ans=max(f[1][n][0],f[1][n][1]);
	if(ans<0) w=0;
	if(w==0){
		cout<<"-";
		ans=-ans;
	}
	cout<<ans/1000;
	cout<<".";
	ans%=1000;
	for(int i=1;i<=3;++i){
		res[i]=ans%10;
		ans/=10;
	}
	for(int i=3;i;--i){
		cout<<res[i];
	}
	return 0;
}
posted @ 2021-08-03 08:52  glq_C  阅读(53)  评论(0)    收藏  举报