zoukankan      html  css  js  c++  java
  • bzoj1833: [ZJOI2010]count 数字计数&&USACO37 Cow Queueing 数数的梦(数位DP)

    难受啊,怎么又遇到我不会的题了(捂脸)

    如题,这是一道数位DP,随便找了个博客居然就是我们大YZ的……果然nb,然后就是改改模版++注释就好的了,直接看注释吧,就是用1~B - 1~A-1而已,枚举全部位然后判一下是不是上限边缘和前导零就OK

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    LL bit[20];
    
    int len,a[20];
    LL as[10],ret[20];//ret表示假如是上限边缘,后面有多少种填的方式 
    LL f[20][2][2];
    //f[k][fg][z]表示当前这个数x,搞到第k位的时候的数目 
    //fg表示该位是不是在上限边缘 z表示目前是否还是前导零
    LL dfs(int x,int k,int fg,int z)
    {
        if(k==len+1)return 0;
        if(f[k][fg][z]!=-1)return f[k][fg][z];
        
        LL ans=0;
        if(fg==1)//如果前面的部分处于上限边缘
        {
            for(int i=0;i<a[k];i++)//不填上限边缘,枚举填什么 
            {
                if(z==1&&i==0)ans+=dfs(x,k+1,0,1);
                else
                {
                    ans+=dfs(x,k+1,0,0);
                    if(i==x)ans+=bit[len-k];
                }
                //如果i是要统计次数的那个数字,而且不是在前导零的时候,而且还不是在上限的边缘
                //那么后面几位的数字有多少种填法x就出现了几次
            }
            //该位填上限边缘
            if(z==1&&a[k]==0)ans+=dfs(x,k+1,1,1);
            else 
            {
                ans+=dfs(x,k+1,1,0);
                if(a[k]==x)ans+=ret[k];
            }
            //如果填的是要统计次数的那个数字 而且不是在前导零的时候
            //那么后面的数字最多有多少种填法x就出现了几次
        }
        else//没有限制
        {
            for(int i=0;i<=9;i++)//同上 
            {
                if(z==1&&i==0)ans+=dfs(x,k+1,0,1);
                else 
                {
                    ans+=dfs(x,k+1,0,0);
                    if(i==x)ans+=bit[len-k];
                }
            }
        }
        f[k][fg][z]=ans;
        return ans;
    }
    char s[20];
    void cl()//把A减1
    {
        int t=len;
        while(t>1&&s[t]=='0'){s[t]='9';t--;}
        s[t]--;
        if(s[t]==0)
        {
            len--;
            for(int i=1;i<=len;i++)s[i]=s[i+1]-'0';
        }
    }
    int main()
    {
        freopen("dream.in","r",stdin);
        freopen("dream.out","w",stdout);
        bit[0]=1;for(int i=1;i<=18;i++)bit[i]=bit[i-1]*10;
        memset(as,0,sizeof(as));
        
        
        scanf("%s",s+1);len=strlen(s+1);cl();
        for(int i=1;i<=len;i++)a[i]=s[i]-'0';
        //0的情况,所以填的方案都要+1 
        ret[len]=1;for(int i=len-1;i>=1;i--)ret[i]=a[i+1]*bit[len-i-1]+ret[i+1];
        for(int i=0;i<=9;i++)
        {
            memset(f,-1,sizeof(f));
            as[i]-=dfs(i,1,1,1);
        }
        
        
        scanf("%s",s+1);len=strlen(s+1);
        for(int i=1;i<=len;i++)a[i]=s[i]-'0';
        
        ret[len]=1;for(int i=len-1;i>=1;i--)ret[i]=a[i+1]*bit[len-i-1]+ret[i+1];
        for(int i=0;i<=9;i++)
        {
            memset(f,-1,sizeof(f));
            as[i]+=dfs(i,1,1,1);
        }
        
        
        for(int i=0;i<9;i++)printf("%d ",as[i]);
        printf("%d
    ",as[9]);
        return 0;
    }
  • 相关阅读:
    day10函数嵌套
    day 9
    day 8函数
    day7预习
    合唱队形(解题思维的锻炼)
    Cow Exhibition (背包中的负数问题)
    Investment(完全背包)
    Cash Machine(多重背包二进制转换)
    Milking Time(DP)
    Brackets Sequence(升级版)
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/7716156.html
Copyright © 2011-2022 走看看