1049. Counting Ones (30)

题目如下:

The task is simple: given any positive integer N, you are supposed to count the total number of 1's in the decimal form of the integers from 1 to N. For example, given N being 12, there are five 1's in 1, 10, 11, and 12.

Input Specification:

Each input file contains one test case which gives the positive N (<=230).

Output Specification:

For each test case, print the number of 1's in one line.

Sample Input:
12
Sample Output:
5


对于此类问题,应当从找一般化的规律为主,而不应当试图推导排序组合的数学表达式。

这道题目的难点在于每一位都有出现1的可能,例如100,010,001,110等,如果按照排序组合考虑,因为要计数1的个数,因此对于1的个数不同,要分别对待,这将会是很棘手的问题。

如果换个思路,从每一位入手,研究每一位的规律,则会使得问题简单得多,这种研究方法是科学的,因为每一位都考虑了自己的1,那么合起来对于多个1的问题就自然考虑进来了,例如N=12时,我们分别考虑下面的情况:

个位出现1的有1,11,十位出现1的有10,11,12,我们看到,对于11这种多个1的情况,正好计算了两次,对于多位也是这个道理。

下面我们从一个5位数入手,研究百位不同时,百位为1的所有情况的计算:

我们以12045、12145、12245为例。
12045:
百位为0,那么高位不变低位部分无法产生类似1XX的数字,因此考虑高位,注意到只要比当前值小就可以,因此可选择:00100-00199,01100-01199 ... 11100-11199 一共12*100=1200,观察到等于比当前高位的数字*100。
也就是:高位数字*100,注意到这个100和当前考虑的位有关,百位为100,从低位为第1位开始计算第x位为10的x次方,也就是说对不同的位这个100应该换成相应的值

12145:
百位为1,那么高位不变,低位从100-145都可以,共45+1=46个,高位仍然可以产生百位为0时的变化,共1200+46+1246种
也就是:高位数字*100 + 低位数字+1
12245:
对于百位大于1的情况,我们只需要考虑高位即可列全所有,从00100-00199到12100-12199,共13*100=1300
也就是:(高位数字 + 1)*100


解决了这个问题,下面要解决的是取出高位数、当前位、低位数的问题,我们以6位数abcdef取出百位为例:

对于abcdef,设因数factor=100,即要取出百位d
按照常规方法,百位 = abcdef / factor % 10 = abcd % 10 = d
高位数字 = abcdef / factor / 10 = abc
低位数字 = abcdef - abcd00 = ef
而abcd00 = (abcdef / factor) * factor = abcd00
所以低位数字 = abcdef - ( abcdef / factor ) * factor

这时候,factor就是前面我们要找的从低位开始算的10的x次方,因此编写代码变得简单,只需要从低位开始,也就是factor从1开始,每次乘以10,直到超出当前值,此时N/factor=0,停止运算。


代码如下:

#include <iostream>
#include <stdio.h>

using namespace std;

int compute(int N){
    int factor = 1;
    int low = 0;
    int high = 0;
    int now = 0;
    int cnt = 0;

    while(N / factor != 0){
        now = (N / factor) % 10;
        high = N / factor / 10;
        low = N - (N / factor) * factor;

        switch(now){
        case 0:
            cnt += high * factor;
            break;
        case 1:
            cnt += high * factor + low + 1;
            break;
        default:
            cnt += (high + 1) * factor;
        }

        factor *= 10;

    }

    return cnt;

}

int main()
{
    int N;
    while(scanf("%d",&N) != EOF){
        cout << compute(N) << endl;
    }

    return 0;
}


你可能感兴趣的:(C++,算法,pat,规律)