题解 P2466 【[SDOI2008]Sue的小球】
考虑先将彩蛋按
首先,很显然的,因为射击不需要时间,所以说最优方案一定不会出现类似于
于是考虑定义
分析一下上面的状态,可以发现我们可以确定已经被收集掉了的彩蛋有哪些。而我们在拓展收集另外一个彩蛋的时候确确实实可以知道哪些彩蛋没有被收集。那么我们能不能将还没有收集的彩蛋下降的分数先加入我们的状态定义呢?
这样是可行的。因为我们能够发现彩蛋下降只会跟当前的时间有关系,所以可以将未来彩蛋下降的负贡献先加入到状态中,这样是没有问题的。
然后再想想怎么转移。对于一个区间
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
struct Egg{
LL x,y,v;
Egg(){x=y=v=0;}
Egg(LL X,LL Y,LL V){x=X,y=Y,v=V;}
bool operator < (Egg ano) const {return x<ano.x;}
}egg[1005];
LL Abs(LL x){return x<0?-x:x;}
LL dp[1005][1005][2],sum[1005][1005],n,firx,totv;
int main(){
memset(dp,128,sizeof dp);
scanf("%lld %lld",&n,&firx);
for(LL i=1;i<=n;++i) scanf("%lld",&egg[i].x);
for(LL i=1;i<=n;++i) scanf("%lld",&egg[i].y);
for(LL i=1;i<=n;++i) scanf("%lld",&egg[i].v),totv+=egg[i].v;
sort(egg+1,egg+1+n);
for(LL i=1;i<=n;++i) for(LL j=i;j<=n;++j) sum[i][j]=sum[i][j-1]+egg[j].v;
for(LL i=1;i<=n;++i) dp[i][i][0]=dp[i][i][1]=egg[i].y-Abs(firx-egg[i].x)*totv;
for(LL dis=2;dis<=n;++dis)
{
for(LL l=1,r=dis;r<=n;++l,++r)
{
dp[l][r][0]=max(dp[l+1][r][0]-(totv-sum[l+1][r])*(egg[l+1].x-egg[l].x),dp[l+1][r][1]-(totv-sum[l+1][r])*(egg[r].x-egg[l].x))+egg[l].y;
dp[l][r][1]=max(dp[l][r-1][0]-(totv-sum[l][r-1])*(egg[r].x-egg[l].x),dp[l][r-1][1]-(totv-sum[l][r-1])*(egg[r].x-egg[r-1].x))+egg[r].y;
}
}
printf("%.3f",double(max(dp[1][n][0],dp[1][n][1]))/1000.0);
return 0;
}