• 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;
    }
    
  • 相关阅读:
    cron表达式
    特殊二叉树和平衡二叉树和树的遍历
    进阶之常见算法和算法题
    原码,反码,补码、移码
    PostgreSQL 大小写问题 一键修改表名、字段名为小写
    ImportError: cannot import name 'PackageFinder' from 'pip._internal.index'
    安装pl/sql developer(内附下载地址)
    oracle plsql的结构
    oracle数据库基本操作
    java的高并发IO原理,阻塞BIO同步非阻塞NIO,异步非阻塞AIO
  • 原文地址:https://www.cnblogs.com/OvOq/p/14853087.html
Copyright © 2020-2023  润新知