【题解】【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;
}

浙公网安备 33010602011771号