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;
}
原文地址:https://www.cnblogs.com/AKCqhzdy/p/7716156.html