[ZJOI2010]count 数字计数

来源:互联网 发布:输入端口 英文 编辑:程序博客网 时间:2024/05/29 04:34

Description
给定两个正整数ab,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次。

Input
输入文件中仅包含一行两个整数ab,含义如上所述。

Output
输出文件中包含一行10个整数,分别表示0-9在[a,b]中出现了多少次。

Sample Input
1 99

Sample Output
9 20 20 20 20 20 20 20 20 20

HINT
30%的数据中,a<=b<=106
100%的数据中,a<=b<=1012

Source
Day1

思路
第一次写数位dp。。。顾名思义,数位dp就是对每个数位进行dp。一般来说,数位dp的适用范围是求一个区间[a,b]的值,其中ab会很大,而且值具有可加性。那么对于每个值可以分成一些段,如:2333可以分成求0-999,1000-1999,2000-2299,2300-2329,2330-2333的值。对于这道题,黄学长博客是这样写的:递推出fi,j,k表示长度为i开头j的所有数字中k的个数。然后分段处理就好了。

代码

#include <cstdio>#include <cmath>const int maxn=12;struct data{    long long num[10];    data operator +(const data &other)    {        data res;        for(int i=0; i<=9; i++)        {            res.num[i]=num[i]+other.num[i];        }        return res;    }};data f[maxn+1][10];long long t[maxn+1],a,b;int init();data calc(long long n);int main(){    init();    scanf("%lld%lld",&a,&b);    data x=calc(a-1),y=calc(b);    for(int i=0; i<9; i++)    {        printf("%lld ",y.num[i]-x.num[i]);    }    printf("%lld\n",y.num[9]-x.num[9]);    return 0;}int init(){    t[1]=1;    for(int i=2; i<=13; i++)    {        t[i]=t[i-1]*10ll;    }    for(int i=0; i<=9; i++)    {        f[1][i].num[i]=1;    }    for(int i=2; i<=12; i++)    {        for(int j=0; j<=9; j++)        {            for(int k=0; k<=9; k++)            {                f[i][k]=f[i][k]+f[i-1][j];                f[i][k].num[k]+=t[i-1];            }        }    }    return 0;}data calc(long long n){    data ans;    ans.num[0]=1;    for(int i=1; i<=9; i++)    {        ans.num[i]=0;    }    if(!n)    {        return ans;    }    int len=log(n)/log(10)+1;    for(int i=1; i<len; i++)    {        for(int j=1; j<=9; j++)        {            ans=ans+f[i][j];        }    }    int h=n/t[len];    n%=t[len];    for(int i=1; i<h; i++)    {        ans=ans+f[len][i];    }    ans.num[h]+=n+1;    for(int i=len-1; i>0; i--)    {        h=n/t[i];        n%=t[i];        for(int j=0; j<h; j++)        {            ans=ans+f[i][j];        }        ans.num[h]+=n+1;    }    return ans;}