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;
}

  

posted @ 2016-11-08 20:31  DUXT  阅读(538)  评论(0编辑  收藏  举报