【Luogu】P1430序列取数(DP)

  题目链接

  博弈DP太喵了qwq

  设f[i][j]表示剩下区间【i,j】要取,先手最大值

  明显我们要从这区间里面拿个最大的

  就等价于这段区间的前缀和,我们要给对手留下个最小的

  就是f[i][j]=sum[i][j]-min(f[i+1][j],f[i+2][j]......f[j][j],f[i][j-1].....f[i][i])

  搞一搞优化可以O(n^2)做

  

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<algorithm>
#define maxn 1020
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

int d[maxn][maxn];
int w[maxn][maxn];
int f[maxn][maxn];
int sum[maxn];

int main(){
    int T=read();    int inf=0x7fffffff;
    while(T--){
        int n=read();
        for(int i=1;i<=n;++i)    sum[i]=read()+sum[i-1];
        for(int len=1;len<=n;++len)
            for(int i=1;i+len-1<=n;++i){
                int j=i+len-1;
                d[i][j]=w[i][j]=inf;
                f[i][j]=sum[j]-sum[i-1]-min(min(d[i][j-1],w[i+1][j]),0);
                if(i==j)    d[i][j]=w[i][j]=sum[j]-sum[j-1];
                else{
                    d[i][j]=min(d[i][j-1],f[i][j]);
                    w[i][j]=min(w[i+1][j],f[i][j]);
                }
            }
        printf("%d\n",f[1][n]);
    }
    return 0;
}

 

posted @ 2018-01-30 20:24  Konoset  阅读(155)  评论(0编辑  收藏  举报