bzoj3315:[Usaco2013 Nov]Pogo-Cow
思路:首先可以写出n^3dp的状态转移方程:f[i][j]=max{f[j][k]+val[i]},f[i][j]表示最后一步跳到点从j点跳到i点的最大价值(状态不能设成f[i],因为j对后面的决策是有影响的),然后枚举k转移,但这样在时限内是无法通过的,于是考虑如何优化dp,可以改变一下枚举顺序,也就是一般的都是先枚举i再枚举j,可以先枚举j再枚举i,这样有什么好处呢,那么k就以直接用一个指针从j-1扫到1,因为随着i的不断增加,i与j之间的距离是递增的,那么之前合法的决策现在也一定合法,那么就可以用一个值记录最大的f[j][k],转移即可。然后还要记得正反做两遍。
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define maxn 1005 int n,ans; int f[maxn][maxn]; inline int read(){ int x=0;char ch=getchar(); for (;ch<'0'||ch>'9';ch=getchar()); for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; return x; } struct node{ int x,v; bool operator <(const node &a)const{return x<a.x;} }a[maxn]; int main(){ n=read(); for (int i=1;i<=n;i++) a[i].x=read(),a[i].v=read(); sort(a+1,a+n+1); for (int j=1;j<=n;j++){ int k=j-1,val=f[j][0]+a[j].v; for (int i=j+1;i<=n;i++){ while (k&&a[i].x-a[j].x>=a[j].x-a[k].x) val=max(val,f[j][k]+a[j].v),k--; f[i][j]=max(f[i][j],val); ans=max(ans,val+a[i].v); } } for (int j=n;j;j--){ int k=j+1,val=f[j][n+1]+a[j].v; for (int i=j-1;i;i--){ while (k<=n&&a[k].x-a[j].x<=a[j].x-a[i].x) val=max(val,f[j][k]+a[j].v),k++; f[i][j]=max(f[i][j],val); ans=max(ans,val+a[i].v); } } printf("%d\n",ans); return 0; }