星辰.Net技术社区论坛

首页 » .NET » 算法/数据结构 » 要求计算 1 到 N 的正整数中包含 0 .. 9 的数目
admin - 2008-7-6 11:07:00
John Smith has decided to number the pages in his notebook from 1 to N. Please, figure out the number of zeros, ones, twos, ... , nines he might need.ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
InputOne number N (N<1000000000)ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
OutputThere should be 10 lines. The first line should contain the number of zeros needed , the second line should contain the number of ones needed, ... , the tenth line should contain the number of nines needed.ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
Sample
inputoutput
12 1ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
5ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
2ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
1ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
1ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
1ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
1ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
1ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
1ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
1ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
Problem Author: Eugene Bryzgalov ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
Problem Source: Ural Collegiate Programming Contest, April 2001, Perm, English Tour 答案如下:ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
1 using System;ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
2 ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
3 namespace Skyiv.Ben.Timusѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
4 {ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
5    // Timus 1150. Digits: 求 1 到 N 的正整数中包含 0 .. 9 的数目。ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
6    // N    9  99 999 9,999 99,999 999,999 9,999,999 99,999,999 999,999,999ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
7    // i*p  1  20 300 4,000 50,000 600,000 7,000,000 80,000,000 900,000,000ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
8    // q    1  11 111 1,111 11,111 111,111 1,111,111 11,111,111 111,111,111ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
9    // 上表中,i*p 是 1 .. 9 的数目,i*p - q 是 0 的数目。ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
10  // http://acm.timus.ru/problem.aspx?space=1&num=1150ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
11  sealed class T1150ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
12   {ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
13    static void Main()ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
14     {ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
15      int[] a = new int[10]; // 0 .. 9 的数目ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
16      int k = 0, n = int.Parse(Console.ReadLine());ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
17      for (int i = 0, m = 1, p = 1, q = 0; n > 0; i++, n /= 10, q = q * 10 + 1)ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
18       {ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
19        int d = n % 10//  d: n 的第 i 位数字,i: 0:个位 1:十位 2:百位 ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
20         k += i * p * d;  // i*p: 0 1 20 300 4000 50000 600000 7000000 ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
21        if (i > 0) p *= 10; // p: 1 1 10 100 1000 10000 100000 1000000 ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
22        for (int j = d - 1; j >= 0; j--) a[j] += p; // 0 .. d-1 的数目ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
23        if (n < 10) a[0] -= p + q; // q: 0 1 11 111 1111 11111 111111 ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
24         a[d] += m;  // d 的数目ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
25         m += d * p; // m: n 的低 i 位 + 1, 例 n: 59842,m: 1 3 43 843 9843ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
26       }ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
27      for (int i = 0; i < a.Length; i++) Console.WriteLine(a+ k);ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
28     }ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
29   }ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
30 }ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
本程序使用的算法是非常高效的,时间复杂度是 O(logN)。主要难点是计算 0 的数目。今天断断续续用了三、四个小时才完全搞定这个算法。ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
上图是输入 N = 59842 的示意图。在这个例子中,i 从 0 循环到 4,分别对应 N 的个、十、百、千、万位。在循环体内,又分为三个部分进行计数。下面以 i = 2,即 N 的百位数 d = 8 为例进行说明:ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
至于 0 的计数,需要在最后一轮循环 ( N 的最高位 ) 中扣除无效前导零,如程序中第 23 行: if (n < 10) a[0] -= p + q;  所示,此时 i = 4,n = 5,p = 10000,q = 1111。扣除 p 是为了上图中黄色部分的 0,扣除 q 是为了上图中浅青色部分的 0。ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
附:上面程序的算法中使用了以下定理:ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
从 1 到 10r - 1 的正整数,包含 1 .. 9 各 r * 10r-1 个,包含 0 的数目为: r * 10r-1 - ( 100 + ... + 10r-1)。 证明如下:ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
以 r = 3 为例,我们来证明从 1 到 999 的正整数,包含 1 .. 9 各 300 个,包含 0 的数目为: 300 -111 = 189。ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
首先,考虑 000 .. 999 这 1000 个整数(暂时不丢弃前导零),每个整数共包含 3 个数字,所以这 1000 个整数包含 3 * 1000 = 3000 个数字。ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
其次,这 1000 个整数中,0 .. 9 这 10 个数字出现的次数是相同的,也就是说, 0 .. 9 这 10 个数字各出现了 3000 / 10 = 300 次。ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
最后,让我们来计算前导零的个数,分为以下三种情况:ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
总计: 3 * 1 + 2 * 9 + 1 * 90 = 1 + (1 + 9) + (1 + 9 + 90) = 1 + 10 + 100 = 111 个。ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
所以,扣除前导零后,包含 0 的数目为: 300 -111 = 189。ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
对于 r 的其他值也可以类似地证明。ѓ1*OowI-www.netcsharp.cn¯ƒ­ívª¶||4
1
查看完整版本: 要求计算 1 到 N 的正整数中包含 0 .. 9 的数目