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;
    }
    
  • 相关阅读:
    java+opencv实现图像灰度化
    java实现高斯平滑
    hdu 3415 单调队列
    POJ 3368 Frequent values 线段树区间合并
    UVA 11795 Mega Man's Mission 状态DP
    UVA 11552 Fewest Flops DP
    UVA 10534 Wavio Sequence DP LIS
    UVA 1424 uvalive 4256 Salesmen 简单DP
    UVA 1099 uvalive 4794 Sharing Chocolate 状态DP
    UVA 1169uvalive 3983 Robotruck 单调队列优化DP
  • 原文地址:https://www.cnblogs.com/OvOq/p/14853087.html
Copyright © 2011-2022 走看看