BZOJ-1833-[ZJOI2010]count 数字计数(数位dp)
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。
Source
题解
一道裸的数位dp
dp[i][j][k]表示长度为i开头为j的数字中k的个数
就当模板啦
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 struct node{ ll a[10]; }; 5 ll a,b; 6 ll t[15]; 7 node dp[15][10]; 8 node operator + (node x,node y){ 9 node t; 10 for (int k=0;k<=9;k++) 11 t.a[k]=x.a[k]+y.a[k]; 12 return t; 13 } 14 node calc(ll x){ 15 node ans; 16 for (int i=0;i<=9;i++) ans.a[i]=0; 17 if (!x){ 18 ans.a[0]=1; 19 return ans; 20 } 21 int len=12; 22 while (t[len]>x) len--; 23 ans.a[0]++; 24 for (int i=1;i<len;i++) 25 for (int j=1;j<=9;j++) 26 ans=ans+dp[i][j]; 27 int cnt=x/t[len]; 28 for (int i=1;i<cnt;i++) 29 ans=ans+dp[len][i]; 30 x%=t[len]; 31 ans.a[cnt]+=x+1; 32 for (int i=len-1;i>=1;i--){ 33 cnt=x/t[i]; 34 for (int j=0;j<cnt;j++) 35 ans=ans+dp[i][j]; 36 x%=t[i]; 37 ans.a[cnt]+=x+1; 38 } 39 return ans; 40 } 41 int main(){ 42 scanf("%lld%lld",&a,&b); 43 t[1]=1; 44 for (int i=2;i<=12;i++) t[i]=t[i-1]*10; 45 for (int i=0;i<=9;i++) 46 dp[1][i].a[i]=1; 47 for (int i=2;i<=12;i++) 48 for (int x=0;x<=9;x++) 49 for (int y=0;y<=9;y++){ 50 dp[i][y]=dp[i][y]+dp[i-1][x]; 51 dp[i][y].a[y]+=t[i-1]; 52 } 53 node s1=calc(b),s2=calc(a-1); 54 for (int i=0;i<9;i++) 55 printf("%lld ",s1.a[i]-s2.a[i]); 56 printf("%lld\n",s1.a[9]-s2.a[9]); 57 return 0; 58 }