首页 > 代码库 > uva 11038

uva 11038

Problem E: How many 0‘s?

A Benedict monk No. 16 writes down the decimal representations of all natural numbers between and including m and n, m ≤ n. How many 0‘s will he write down?

Input consists of a sequence of lines. Each line contains two unsigned 32-bit integers m and n, m ≤ n. The last line of input has the value of mnegative and this line should not be processed.

For each line of input print one line of output with one integer number giving the number of 0‘s written down by the monk.

Sample input

10 11100 2000 5001234567890 23456789010 4294967295-1 -1

Output for sample input

12292


大意:

给出若干区间 [L, R] 求出将 L~ R 之间的数全部写出来要用多少个 ‘0‘ ?

思路:

数学特别渣....于是决定现在开始版切掉 lrj 的数学专题....

第一个思想就是采用减法间接计算, 不直接计算.

第二个思想就是分类统计....

  把这个数字分开成三段考虑.

  left, i, right. (left != 0)

  如果 i >= 0, 那么不难想到, 这一位上的 0 出现了 10right.len * left 次.(len 表示 right 有几位)

  如果 i == 0, 那么第 i 位的贡献是: 10right.len * (left - 1) + right 次.

  由于不同的位上互不影响,所以用加法原理加起来就 ok 了.

代码应该还能精简一点.

技术分享
 1 #include<cstdlib> 2 #include<cstdio> 3 #include<algorithm> 4 #include<iostream> 5 using namespace std; 6 typedef long long ll; 7 ll n,m; 8 ll ans(ll x){ 9     ll t = 1,cnt = 0,tmp = x;10     while(tmp){        11         cnt += max((x / (t * 10) - (tmp % 10 == 0)) * t,0LL);12         if(tmp % 10 == 0) cnt += x % t + 1;13         t *= 10, tmp /= 10;14     }15     return cnt;16 }17 int main()18 {19     freopen("0.in","r",stdin);20     freopen("0.out","w",stdout);21     while(cin >> n >> m, m > 0){22         ll a = ans(m), b = ans(n-1), c = n == 0;23         cout << a - b + c << endl;24     }25     return 0;26 }
View Code

 

uva 11038