【题解】[SDOI2008]Sue的小球
\(\text{Solution:}\)
长得很像区间 \(dp\) 对吧,那猜的也差不多了。
注意到有一个全局的总时间对答案造成影响,考虑把它给计算进 \(dp\) 值里面。
也就是 \(2009\) 年论文说到的:
费用提前计算
其实是一个很简单的套路:把每一次转移消耗的时间造成的损耗加进 \(dp\) 值里面,这就可以省去 \(dp\) 状态中的时间这个维度了。
所以自然设计出状态: \(dp[l][r][0/1]\) 表示完成区间 \([l,r]\) 内所有球,且当前人在左边/右边的最大价值。
转移直接看代码吧,比较显然。
细节要注意:原来的错误原因是因为在 int
类型下把最大值设为了 \(2^{31}-1\) 导致运算的时候自然溢出导致错误,开 long long
就对了。
错误特征:会输出一个和你设计的 \(dp\) 数组赋给的最值相反符号的数。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef double db;
const int MAXN=1.5e3+10;
const db eps=1e-10;
const int dyx=1LL<<50;
namespace DyxAkIOI {
int n,pos,sum[MAXN];
struct point {
int x,y,v;
point(){x=0;y=0;v=0;}
bool operator<(const point&B)const{
return x<B.x;
}
} p[MAXN];
int sumv[MAXN];
int f[MAXN][MAXN][2];
inline int Max(int x,int y){return x>y?x:y;}
inline int Min(int x,int y){return x<y?x:y;}
inline int read() {
int s=0,w=1;
char ch=getchar();
while(!isdigit(ch)) {
if(ch=='-')w=-1;
ch=getchar();
}
while(isdigit(ch)) {
s=s*10-48+ch;
ch=getchar();
}
return s*w;
}
int getspeed(int l,int r){
return sumv[r]-sumv[l-1];
}
void Init() {
n=read();
pos=read();
for(int i=1;i<=n;++i)p[i].x=read();
for(int i=1;i<=n;++i)p[i].y=read();
for(int i=1;i<=n;++i)p[i].v=read();
p[++n].x=pos;
sort(p+1,p+n+1);
int P;
for(int i=1;i<=n;++i){
sumv[i]=sumv[i-1]+p[i].v;
if(p[i].x==pos)P=i;
}
for(int i=0;i<=n+1;++i)
for(int j=0;j<=n+1;++j)
f[i][j][0]=f[i][j][1]=-dyx;
f[P][P][0]=0;f[P][P][1]=0;
for(int len=2;len<=n;++len){
for(int l=1;l<=n-len+1;++l){
int r=l+len-1;
f[l][r][0]=p[l].y+Max(f[l+1][r][1]-(sumv[n]-getspeed(l+1,r))*(p[r].x-p[l].x),f[l+1][r][0]-(sumv[n]-getspeed(l+1,r))*(p[l+1].x-p[l].x));
f[l][r][1]=p[r].y+Max(f[l][r-1][0]-(sumv[n]-getspeed(l,r-1))*(p[r].x-p[l].x),f[l][r-1][1]-(sumv[n]-getspeed(l,r-1))*(p[r].x-p[r-1].x));
}
}
// cout<<Max(f[1][n][0],f[1][n][1])<<endl;
// for(int i=1;i<=n;++i)
// for(int j=1;j<=n;++j)
// printf("%d %d %c",f[i][j][0],f[i][j][1],j==n?'\n':' ');
printf("%.3lf\n",(double)(Max(f[1][n][0],f[1][n][1]))/1000.0);
}
}
signed main() {
// freopen("111.txt","r",stdin);
DyxAkIOI::Init();
return 0;
}