先送个大爷的题解传送门
显然在经过了l点和r点之后,[l,r]中途的点也是经过了的,并不会有任何贡献,于是可以用f[l][r]来记录这一段的贡献,还要记录当前是在左端点还是右端点,于是再开一维0..1就好了
每次转移到 l-1和r+1,转移的代价就是当前未经过的点在转移的时间里减少的价值。
BZOJ 1694直接用数量就好,2037开个前缀和瞎搞搞就好
注意给出的数据是无序的
1694:
#include<bits/stdc++.h>
#define MAXN 1005
#define INF 0x3f3f3f3f
using namespace std; int n,l;
int p[MAXN];
int f[MAXN][MAXN][2];
int main(){
scanf("%d%d",&n,&l);
for(int i=1;i<=n;++i) scanf("%d",p+i);
sort(p+1,p+n+1);
memset(f,INF,sizeof f);
for(int i=1;i<=n;++i) f[i][i][0] = f[i][i][1] = abs(l-p[i])*n;
for(int i=2;i<=n;++i){
for(int l=1,r=i;r<=n;++l,++r){
f[l][r][0] = min(f[l+1][r][0] + (p[l+1]-p[l]) * (n-i+1),
f[l+1][r][1] + (p[r]-p[l]) * (n-i+1));
f[l][r][1] = min(f[l][r-1][0] + (p[r]-p[l]) * (n-i+1),
f[l][r-1][1] + (p[r]-p[r-1]) * (n-i+1));
}
}
printf("%d",min(f[1][n][0],f[1][n][1]));
return 0;
}
2037:
#include<bits/stdc++.h>
#define MAXN 1005
using namespace std; int n,x0;
struct t1{
int x,v;
bool operator < (const t1 &ano) const{
return x<ano.x;
}
}dt[MAXN];
int a[MAXN],b;
int f[MAXN][MAXN][2];
int sum[MAXN];
int ans = 0;
int main(){
// freopen("1.in","r",stdin);
scanf("%d%d",&n,&x0);
for(int i=1;i<=n;++i) scanf("%d",&dt[i].x);
for(int i=1;i<=n;++i) scanf("%d",&b) , ans += b;
for(int i=1;i<=n;++i) scanf("%d",&dt[i].v);
sort(dt+1,dt+n+1);
for(int i=1;i<=n;++i) a[i] = dt[i].x;
for(int i=1;i<=n;++i) sum[i] = sum[i-1] + dt[i].v;
for(int i=1;i<=n;++i) f[i][i][0] = f[i][i][1] = abs(x0 - a[i]) * sum[n];
for(int i=2;i<=n;++i)
for(int l=1,r=i;r<=n;++l,++r){
f[l][r][0] = min( f[l+1][r][0] + (a[l+1] - a[l]) * (sum[n] - sum[r] + sum[l]),
f[l+1][r][1] + (a[r] - a[l]) * (sum[n] - sum[r] + sum[l]));
f[l][r][1] = min( f[l][r-1][0] + (a[r] - a[l]) * (sum[n] - sum[r-1] + sum[l-1]),
f[l][r-1][1] + (a[r] - a[r-1]) * (sum[n] - sum[r-1] + sum[l-1]));
}
printf("%.3f",(double)(ans - min(f[1][n][0],f[1][n][1]))/1000);
return 0;
}