Description
给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次。Input
输入文件中仅包含一行两个整数a、b,含义如上所述。Output
输出文件中包含一行10个整数,分别表示0-9在[a,b]中出现了多少次。Sample Input
1 99Sample Output
9 20 20 20 20 20 20 20 20 20HINT
30%的数据中,a<=b<=106; 100%的数据中,a<=b<=1012。Source
Day1思路
第一次写数位dp。。。顾名思义,数位dp就是对每个数位进行dp。一般来说,数位dp的适用范围是求一个区间[a,b]的值,其中a和b会很大,而且值具有可加性。那么对于每个值可以分成一些段,如:2333可以分成求0-999,1000-1999,2000-2299,2300-2329,2330-2333的值。对于这道题,是这样写的:递推出fi,j,k表示长度为i开头j的所有数字中k的个数。然后分段处理就好了。代码
#include#include 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 0; i--) { h=n/t[i]; n%=t[i]; for(int j=0; j