Description
已知两个正整数a和b,求在a与b之间(包含a和b)的所有整数的十进制表示中1出现的次数。
Input
多组数据(不超过100000组),每组数据2个整数a,b.(1≤a,b≤1000000).
Output
每组数据的答案占一行。
Sample Input
1 10 10 100 2 1
Sample Output
2 20 1
题目大意:给出两个数,求这两个数之间的十进制数中1出现的个数。
//看完不会,如果是二进制数出现的个数那就简单了。
前缀和问题:
https://blog.csdn.net/K_rew/article/details/50527287#commentBox
一维前缀和,主要是在O(1)时间内求出a[i]+a[i+1]....+a[j]的和,那么就是sum[j]-sum[i-1].
一般是在数据量很大的时候,不能挨个去遍历,那么就需要先求出前缀和来进行降低复杂度。
代码来自:https://blog.csdn.net/bobo1356/article/details/71105934
前缀和是一种预处理手段,空间换时间。
#include<iostream> #include<stdio.h> using namespace std; const int maxn = 1e6+1; int sum[maxn]; //sum[i]表示前i个数中所包含的1出现的次数之和 //cal函数求a中所包含的1的个数 int cal(int a)//这个只是计算每个数中包含的1的个数。使用%即可。 { int cnt = 0; while(a) { if(a%10 == 1) cnt++; a /= 10; } return cnt; } int main() { //求sum[0]-sum[1e6]的值 sum[0] = 0; for(int i=1; i<=1e6; i++)//可以不写六个0,而使用这种形式。 { sum[i] = sum[i-1] + cal(i); } int a,b; while(scanf("%d%d",&a,&b) != EOF) { if(a>b) { int tmp = a; a = b; b = tmp; } printf("%d\n",sum[b]-sum[a-1]); } return 0; }
//这样就降低了时间复杂度,过程是这样的,由于输入中最多包含1e5次组数据,并且每个的最大范围为0-1e6,那么进行三个假设,
假设数据组数为T,a,b的范围为N,a~b中间的每一个数需要进行M次运算,那么此时为O(T*M*N)
但是如果使用了前缀和,计算sum[i]=sum[i-1]+cal[i];//那么以后每次就可以查询了
变为了:O(1*T)+O(N*M)
注意前一项中,每组数据查询都是O(1)的复杂度,所以是O(1*T);
后一项中,是进行预处理的复杂度,就不会超时了。
//真的是很厉害了!膜一下~