【POJ2282 The Counting Problem】求区间[a,b]中每个数字出现的次数

题目链接:http://poj.org/problem?id=2282

 

题目大意:给你两个数a,b,让你计算a到b之间所有的数总共包含多少0~9。

 

解题思路:  蛋疼的人生蛋疼的题。可以分别统计[0,b]中包含多少个0~9,[0,a]中包含多少个0~9,两个求得的结果相减就是答案了。

         举例分析: 299 百位数字有0,1,2,那么它们在百位时分别出现了100次,再对十位数和个位数的99分析,因为[0,99]中0~9出现的频率都是一样的,

分别为2(前一个数的值)*(位数)*10(固定一个数其余位能变化的次数)。

         所以对于4567,我们可以这样拆:0~3999,4000~4499,4500~4559,~4560~4567 。求得得总和就是答案了,还要注意一点的是前导0不能加进去,注意把加进去多余的前导0减掉。

View Code
 1 #include <iostream>

 2 #include <cstdio>

 3 #include <cstring>

 4 #include <sstream>

 5 #include <algorithm>

 6 using namespace std;

 7 

 8 void Cal(string s, int *num)

 9 {

10     int k=1;

11     for(int i=0; i<s.size()-1; i++)

12        k*=10, num[0]-=k;

13     for(int i=0; i<s.size(); i++,k/=10)

14     {

15         for(int j=0; j<s[i]-'0'; j++)

16             num[j]+=k;

17         for(int j=0; j<10; j++)

18             num[j]+=k/10*(s.size()-i-1)*(s[i]-'0'); ///!!这里要注意对于0~2999,[0,999]不仅要乘以位数还要乘以他前一位的值,指出现了多少次[0,999]

19         for(int j=0; j<i; j++)

20             num[s[j]-'0']+=(s[i]-'0')*k;  

21         num[s[i]-'0']++;  ///末尾都是0的情况

22     }

23 }

24 

25 int main()

26 {

27     int n, m;

28     string s;

29     int a[10], b[10];

30     while(~scanf("%d%d",&n,&m),n+m)

31     {

32         memset(a,0,sizeof(a));

33         memset(b,0,sizeof(b));

34         stringstream sa, sb;   ///中间过度函数,将int,double之类的类型转换成string

35         if(n>m) swap(n,m);

36         sa << n-1;

37         s=sa.str();  

38         Cal(s,a);

39         sb<<m;

40         s=sb.str();

41         Cal(s,b);

42         for(int i=0; i<10; i++)

43         {

44             if(i!=9) printf("%d ",b[i]-a[i]);

45             else printf("%d\n",b[i]-a[i]);

46         }

47     }

48     return 0;

49 }

 

补充解释

 1 #include <iostream>

 2 #include <sstream>

 3 #include <cstring>

 4 using  namespace std;

 5 

 6 ///以3456分析,3456可以划分为0~2999,3000~3399,3400~3449,3450~3456

 7 void Cal(string s, int* num)

 8 {

 9     int k=1;

10     for(int i=0; i<s.size(); i++)

11         k*=10, num[0]-=k;              ///去除去0作为前导的情况

12     for(int i=0; i<s.size(); i++, k/=10)

13     {

14         for(int j=0; j<s[i]-'0'; j++)  ///第i位时,对最高位进行分析,比如0~2999,最高位0和1都出现了1000次。

15             num[j]+=k;

16         for(int j=0; j<10; j++)  ///对0~2999分析,[0,999]中0~9出现的概率一样,最高位大小(2)*位数(3)*固定一位的最多次数(100)

17             num[j]+=(s[i]-'0')*(s.size()-i-1)*k/10;

18         for(int j=0; j<i; j++)    ///对于前面的每一位,还要后续处理后面没处理到的情况,比如处理最高位3时只处理了0~2999,而没有处理3000~3399,3400~3449,3450~3456等情况,后面处理的时候要考虑到

19             num[ s[j]-'0' ]+=(s[i]-'0')*k;

20         num[ s[i]-'0' ]++;  ///末尾都是0的情况

21     }

22 }

23 

24 int main()

25 {

26     int n;

27     int num[10];

28     while(cin >> n)

29     {

30         stringstream sa;

31         memset(num,0,sizeof(num));

32         string str;

33         sa << n;

34         sa >> str;

35         Cal(str,num);

36         for(int i=0; i<10; i++)

37             cout << num[i] <<endl;

38     }

39 }
View Code

 

你可能感兴趣的:(count)