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 }
View Code

 

posted @ 2017-10-27 15:10  I__am  阅读(189)  评论(0编辑  收藏  举报