[ZJOI2010]数字计数

题目描述

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1: 复制
1 99
输出样例#1: 复制
9 20 20 20 20 20 20 20 20 20

说明

30%的数据中,a<=b<=10^6;

100%的数据中,a<=b<=10^12。

数位dp的套路记忆化搜索

枚举d=0~9,分别统计

f[pos][sum]表示当前在pos位,d这个数出现个数

flag表示是否限位,k表示是否前导0

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 typedef long long lol;
 8 int s[13],len;
 9 lol A,B,f[21][21];
10 lol dfs(int pos,int sum,int flag,int k,int d)
11 {int i;
12   lol cnt=0;
13   if (pos<=0) return sum;
14   if (!flag&&k&&f[pos][sum]!=-1) return f[pos][sum];
15   int ed=9;
16   if (flag) ed=s[pos];
17   for (i=0;i<=ed;i++)
18     {
19       if (k==0&&i==0)
20     cnt+=dfs(pos-1,sum,flag&&(i==ed),0,d);
21       else
22     {
23       cnt+=dfs(pos-1,sum+(i==d),flag&&(i==ed),1,d);
24     }
25     }
26   if (!flag&&k) f[pos][sum]=cnt;
27   return cnt;
28 }
29 lol solve(lol x,int d)
30 {int i,j,k;
31   memset(f,-1,sizeof(f));
32   len=0;
33   while (x)
34     {
35       s[++len]=x%10;
36       x/=10;
37     }
38   return dfs(len,0,1,0,d);
39 }
40 int main()
41 {int i;
42   cin>>A>>B;
43   printf("%lld",solve(B,0)-solve(A-1,0));
44   for (i=1;i<=9;i++)
45     {
46       printf(" %lld",solve(B,i)-solve(A-1,i));
47     }
48 }

 

posted @ 2018-03-01 12:00  Z-Y-Y-S  阅读(257)  评论(0编辑  收藏  举报