【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 }