zoukankan      html  css  js  c++  java
  • codeforces1068——D.Array Without Local Maximums(计数DP+前缀和优化)

    原题链接
    题意:
    给定一个序列,a[i]==-1表示该位无元素。现在要你填充这个序列使得a[i]<=max(a[i+1],a[i-1]),a[0]=a[n+1]=0
    (最后一句可以这样理解)
    1<=a[i]<=200.求方案数
    思路:
    计数DP,推了好久,还没想到前缀和优化。
    首先是状态表示,因为a[i]的范围只有200,我们不妨来枚举填1~200的每一种情况:dp[i][j][k]表示第i个数填j时并且和第i-1个数的关系为k的方案数,当然这肯定是只有需要填数时才可以转移。
    接下来是状态转移,我们考虑a[i-1]的合法性来进行转移:
    1.当k=0时,表示a[i]>a[i-1],这时候第i-1个数只能从[1,j-1]里选择,因为a[i-1]<a[i]一定成立了,所以a[i-1]和a[i-2]的关系可以是大于,小于和等于。
    2.当k=1时,表示a[i]==a[i-1],这时候只能从dp[i-1][j]转移过来了,同时对于a[i-2]来说,k=0/1/2都成立。
    3.当k=2时,表示a[i]<a[i-1],这时候第i-1个数只能从[j+1,200]里选了,同时因为a[i-1]>a[i],所以a[i-1]<=a[i-2]必须满足,即k=1/2。
    关于初始化,如果a[1]=-1的话,说明该位可以填充,就dp[1][j][0]=1,我们可以理解为a[0]=0,所以第1个数填j(1<=j<=200)的方案数就是1;如果a[1]原本有数的话,就dp[1][a[1][0]=1.
    最后是优化: 上面算法的复杂度是O(200 *200 *n),我们可以对情况1和情况3用前缀和优化。
    代码:

    const int maxn=1e5+100;
    ///a[i]<=a[i-1]
    ///dp[i][j][k]表示第i个数选j和第i-1个数的关系是k的方案数
    ///k==0 a[i]>a[i-1]  dp[i-1][1~j-1][0/1/2]
    ///k==1 a[i]==a[i-1] dp[i-1][j][0/1/2]
    ///k==2 a[i]<a[i-1]  dp[i-1][j+1~200][1/2]
    ll dp[maxn][205][3];
    ll a[maxn],n;
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++) a[i]=read();
        if(a[1]!=-1) dp[1][a[1]][0]=1;///该位无需填充
        else///该位需要填充
            for(int i=1;i<=200;i++) dp[1][i][0]=1;
        for(int i=2;i<=n;i++){///枚举当前填充到第几个数了
            ll sum=0;
            for(int j=1;j<=200;j++){
                if(a[i]==-1||a[i]==j) dp[i][j][0]=sum;///可以填充或是该位正好为枚举的数
                sum=(sum+dp[i-1][j][0]+dp[i-1][j][1]+dp[i-1][j][2])%mod;
            }
            sum=0;
            for(int j=1;j<=200;j++){
                if(a[i]==-1||a[i]==j)
                    dp[i][j][1]=(dp[i-1][j][0]+dp[i-1][j][1]+dp[i-1][j][2])%mod;
            }
            for(int j=200;j;j--){
                if(a[i]==-1||a[i]==j) dp[i][j][2]=sum;
                sum=(sum+dp[i-1][j][1]+dp[i-1][j][2])%mod;
            }
        }
        ll res=0;
        for(int i=1;i<=200;i++)
            res=(res+dp[n][i][1]+dp[n][i][2])%mod;
        out(res);
        return 0;
    }
    
  • 相关阅读:
    P1121 环状最大两段子段和
    无题
    cdoj 1485 柱爷搞子串 sam treap
    自然数幂和
    Gym 100341C AVL Trees NTT
    线性筛分解质因子
    codeforces 366 Ant Man dp
    UVALive 6914 Maze Mayhem 轮廓线dp
    hdu 5790 Prefix 字典树 主席树
    莫比乌斯反演个人小结
  • 原文地址:https://www.cnblogs.com/OvOq/p/14853087.html
Copyright © 2011-2022 走看看