zoukankan      html  css  js  c++  java
  • 【DP优化】【P1430】序列取数

    传送门

    Description

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

    Input

    第一行,一个正整数T,表示有T组数据。
    接着T行,每行第一个数为n,接着n个整数表示给定的序列.

    Output

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

    Sample Input

    2
    1 -1
    2 1 2
    

    Sample Output

    -1
    3
    

    Hint

    时限3s。
    对于100%的数据,(n leq 1000, T leq 100)

    Solution

    显然是博弈DP。考虑设(f_{i,j})是区间([i,j])先手取数的最大答案。转移显然为
    (f_{i,j}=sum_j-sum_i-min{f_{k,j},f_{i,k}}),其中满足(i~<~k~<~j)。枚举(k)进行转移,复杂度是(O(n^3))。直接凉凉。
    状态已经是(O(n^2))无法优化。考虑对转移进行优化。考虑枚举(k)是求一定区间内(f)的最大值。这个(f)的区间是从小到大枚举的,所以可以维护区间内(f)的最大值。具体的,设(l_{i,j})代表(max{f_{i,k}})(r_{i,j})代表(max{f_{k,r}}),其中满足(i~<~k~<~j)
    这样转移方程就变成(f_{i,j}=sum_j-sum_i-min{l_{i,j},r_{i,j}})。这样使用DP对DP进行优化,转移变成(O(1))的,可以通过本题。
    其中(l_{i,j}=max{l_{i,j-1},f_{i,j}})(r)的转移同理。

    Code

    #include<cstdio>
    #include<cstring> 
    #define rg register
    #define ci const int
    #define cl const long long int
    
    typedef long long int ll;
    
    namespace IO {
        char buf[50];
    }
    
    template<typename T>
    inline void qr(T &x) {
        char ch=getchar(),lst=' ';
        while(ch>'9'||ch<'0') lst=ch,ch=getchar();
        while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        if (lst=='-') x=-x;
    }
    
    template<typename T>
    inline void write(T x,const char aft,const bool pt) {
        if(x<0) {putchar('-');x=-x;}
        int top=0;
        do {
            IO::buf[++top]=x%10+'0';
            x/=10;
        } while(x);
        while(top) putchar(IO::buf[top--]);
        if(pt) putchar(aft);
    }
    
    template <typename T>
    inline T mmax(const T a,const T b) {if(a>b) return a;return b;}
    template <typename T>
    inline T mmin(const T a,const T b) {if(a<b) return a;return b;}
    template <typename T>
    inline T mabs(const T a) {if(a<0) return -a;return a;}
    
    template <typename T>
    inline void mswap(T &a,T &b) {T temp=a;a=b;b=temp;}
    
    const int maxn = 1010;
    
    int t,n;
    int MU[maxn],frog[maxn][maxn],lmax[maxn][maxn],rmax[maxn][maxn],sum[maxn];
    
    void clear();
    
    int main() {
        qr(t);
        while(t--) {
            clear() ;
            qr(n);
            for(rg int i=1;i<=n;++i) qr(MU[i]);
            for(rg int i=1;i<=n;++i) lmax[i][i]=rmax[i][i]=frog[i][i]=MU[i],sum[i]=sum[i-1]+MU[i];
            for(rg int i=1;i<n;++i) {
                for(rg int j=1;j<n;++j) {
                    rg int r=i+j;if(r>n) break;
                    frog[j][r]=sum[r]-sum[j-1]-mmin(0,mmin(lmax[j][r-1],rmax[j+1][r]));
                    lmax[j][r]=mmin(frog[j][r],lmax[j][r-1]);rmax[j][r]=mmin(frog[j][r],rmax[j+1][r]);
                }
            }
            write(frog[1][n],'
    ',true);
        }
        return 0;
    }
    
    void clear() {
        memset(MU,0,sizeof MU);
        memset(sum,0,sizeof sum);
        memset(frog,0,sizeof frog);
        memset(lmax,0,sizeof lmax);
        memset(rmax,0,sizeof rmax);
        n=0;
    }
    

    Summary

    在DP因为复杂度较高而无法承受时,考虑对转移进行优化。常见的如维护区间最大/最小值,通过数据结构或者DP进行优化。

  • 相关阅读:
    sort和uniq去重操作【转】
    MySQL中interactive_timeout和wait_timeout的区别【转】
    Keepalived详解(五):Keepalived集群中MASTER和BACKUP角色选举策略【转】
    Keepalived详解(四):通过vrrp_script实现对集群资源的监控【转】
    Keepalived详解(三):Keepalived基础功能应用实例【转】
    Spring详解(六)------AspectJ 实现AOP
    深入理解计算机系统(1.3)------操作系统的抽象概念
    深入理解计算机系统(1.2)------存储设备
    深入理解计算机系统(1.1)------Hello World 是如何运行的
    深入理解计算机系统(序章)------谈程序员为什么要懂底层计算机结构
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/9570829.html
Copyright © 2011-2022 走看看