BSOJ: 2697 -- 【ZJOI2010】数字计数

来源:互联网 发布:远程软件xt800 编辑:程序博客网 时间:2024/05/29 03:16

Description

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

Input

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

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<=10^6;
  100%的数据中,a<=b<=10^12。
  
很裸的数位DP,好久都没刷过题了,居然搞了半小时。
我开了四维的数组,不知道还能不能优化。
p是要计算出现个数的数字09
sum是之前这个数字出现次数。
flag1是判断之前有没有非0数,主要是为了针对0的计算。
建议人工模拟下,更能理解。
代码如下:

#include<cstdio>#include<iostream>#include<cmath>#include<cstdlib>#include<ctime>#include<cstring>#include<algorithm>#include<queue>#include<map>using namespace std;long long F[20][10][15][2]; int c[100];long long Cal(int x,int p,int sum,int flag1,int flag){    if(!x)return sum;    if(!flag&&F[x][p][sum][flag1])return F[x][p][sum][flag1];    int k=flag?c[x]:9;    long long ret=0;    for(int i=0;i<=k;i++){        ret+=Cal(x-1,p,sum+((i==p)&&((flag1&&p==0)||(p!=0))),flag1||(i!=0),flag&&(i==k));    }    return flag?ret:F[x][p][sum][flag1]=ret;}long long Ask(long long x,int k){    c[0]=0;    while(x){c[++c[0]]=x%10;x/=10;}    return Cal(c[0],k,0,0,1);}int main(){    long long a,b;    scanf("%lld%lld",&a,&b);    for(int i=0;i<=9;i++){        printf("%lld ",Ask(b,i)-Ask(a-1,i));    }    return 0;}
0 0
原创粉丝点击