BZOJ1833: [ZJOI2010]count 数字计数

【传送门:BZOJ1833


简要题意:

  给出l,r,求出l到r中0到9的数字出现的次数


题解:

  数位DP,设f[i][j][k]为i位数,最高位为j,k出现的次数

  需要注意一下前导零的问题


参考代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
using namespace std;
typedef long long LL;
LL f[13][10][10];//第i位为j时,有多少个k
LL cf(int b)
{
    LL a=10,ans=1;
    while(b!=0)
    {
        if(b%2==1) ans*=a;
        a*=a;b/=2;
    }
    return ans;
}
void getdp()
{
    for(int i=0;i<=9;i++) f[1][i][i]=1;
    for(int i=2;i<=12;i++)
    {
        for(int j=0;j<=9;j++)
        {
            for(int k=0;k<=9;k++)
            {
                if(j==k) f[i][j][k]=cf(i-1);
                for(int t=0;t<=9;t++) f[i][j][k]+=f[i-1][t][k];
            }
        }
    }
}
int a[13],cnt;
LL ans[11];
void solve(LL d,int t)
{
    cnt=0;LL sum=d;
    if(d!=0) ans[0]+=t*1;
    while(d!=0)
    {
        a[++cnt]=d%10;
        d/=10;
    }
    for(int i=1;i<cnt;i++)
    {
        for(int j=1;j<=9;j++)
        {
            for(int k=0;k<=9;k++) ans[k]+=t*f[i][j][k];//位数小,无前导零 
        }
    }
    for(int i=1;i<a[cnt];i++)
    {
        for(int j=0;j<=9;j++) ans[j]+=t*f[cnt][i][j];//最高位且不为零 
    }
    sum-=a[cnt]*cf(cnt-1);
    ans[a[cnt]]+=t*(sum+1);
    for(int i=cnt-1;i>=1;i--)
    {
        for(int j=0;j<a[i];j++)
        {
            for(int k=0;k<=9;k++) ans[k]+=t*f[i][j][k];
        }
        sum-=a[i]*cf(i-1);
        ans[a[i]]+=t*(sum+1);
    }
}
int main()
{
    getdp();
    LL a,b;
    scanf("%lld%lld",&a,&b);
    solve(a-1,-1);
    solve(b,1);
    for(int i=0;i<9;i++) printf("%lld ",ans[i]);
    printf("%lld\n",ans[9]);
    return 0;
}

 

posted @ 2018-04-18 08:58  Star_Feel  阅读(206)  评论(0编辑  收藏  举报