• 洛谷 P1430 序列取数 解题报告


    P1430 序列取数

    题目描述

    给定一个长为(n)的整数序列((n<=1000)),由(A)(B)轮流取数((A)先取)。每个人可从序列的左端或右端取若干个数(至少一个),但不能两端都取。所有数都被取走后,两人分别统计所取数的和作为各自的得分。假设(A)(B)都足够聪明,都使自己得分尽量高,求(A)的最终得分。

    输入输出格式

    输入格式:

    第一行,一个正整数(T),表示有(T)组数据。((T<=100))

    接着(T)行,每行第一个数为(n),接着(n)个整数表示给定的序列.

    输出格式:

    输出(T)行,每行一个整数,表示(A)的得分


    看到足够聪明,我下意识以为是博弈论。。

    但是似乎并不是,而且我想不出来怎么做。


    对于取剩下的子序列([i,j]),先手有一个可求的最大得分值。

    (dp[i][j])为子序列([i,j])时,先手取可得的最大分数。

    (dp[i][j]=max(sum[i][j],sum[i][j]-min{dp[i+k_1][j],dp[i][j-k_2],k_1in[1,j-i],k_2in[1,j-i]}))

    分别对应先手者(于此步的)选全部,选左边的一段选右边的一段三种情况。

    我们发现这是三维的,需要枚举(k)

    优化?

    (l[i][j])维护(min{dp[i+k_1][j],k_1in[1,j-i]})

    (r[i][j])维护(min{dp[i][j-k_2],k_2in[1,j-i]})

    当然,这两个东西的更新都是(O(1))

    细节:注意区间DP的枚举顺序性


    code:

    #include <cstdio>
    #include <cstring>
    const int N=1010;
    int max(int x,int y) {return x>y?x:y;}
    int min(int x,int y) {return x>y?y:x;}
    int n,t;
    int a[N],f[N],dp[N][N],l[N][N],r[N][N];
    //l[i][j]=min{dp[i][j],dp[i+1][j]...dp[j][j]};
    int read()
    {
        int x=0,ff=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-') ff=-1;c=getchar();}
        while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
        return ff*x;
    }
    
    int main()
    {
        t=read();
        for(int k=1;k<=t;k++)
        {
            n=read();
            memset(f,0,sizeof(f));
            memset(dp,0,sizeof(dp));
            memset(l,0,sizeof(l));
            memset(r,0,sizeof(r));
            for(int i=1;i<=n;i++)
            {
                a[i]=read();
                f[i]=f[i-1]+a[i];
            }
            for(int i=1;i<=n;i++)
            {
                dp[i][i]=a[i];
                l[i][i]=a[i];
                r[i][i]=a[i];
            }
            for(int i=n-1;i>=1;i--)
                for(int j=i+1;j<=n;j++)
                {
                    int sum=f[j]-f[i-1];
                    dp[i][j]=max(sum,max(sum-l[i+1][j],sum-r[i][j-1]));
                    l[i][j]=min(l[i+1][j],dp[i][j]);
                    r[i][j]=min(r[i][j-1],dp[i][j]);
                }
            printf("%d
    ",dp[1][n]);
        }
        return 0;
    }
    
    

    2018.5.1

  • 相关阅读:
    五分钟上手Markdown
    css中居中方法小结
    事务和同步锁
    插入排序
    插入排序
    交换排序
    eclipse 常用快捷键
    交换排序
    二叉搜索树(BST)
    二叉树遍历以及根据前序遍历序列反向生成二叉树
  • 原文地址:https://www.cnblogs.com/butterflydew/p/8999796.html
Copyright © 2020-2023  润新知