统计1到N之间所有十进制数中数字1的个数。

这是一道十分有趣的题,例如N为12的时候,输出是5,因为从1到12,总共有1,10,11,12中包含数字1,总共是5个。

最傻逼的办法当让是直接枚举,即N^2的方法,对于小数据,是可以容忍的,但是此题中N最大可以达到2^30次方,因此

该方法不行。

 

我觉得这一题更偏数学一点,只要找到了递推公式,变成是非常简单的。

我们用part1来表示1-99..99中所包含的1的个数

1-9中有只有1一个

1-99总共有20个

递推公式很容易得到,part1[n] = part1[n-1]*10 + 10^(n-1),其中N表示9的个数。

对于N,我们从N的个位数开始往高位递推。

如下图所示

 

假设我们已经进行到n位,我们用part2表示前n位的结果。N的第n位数字是t,那么前N位的结果

part2[n] = part2[n-1] + t*part1[n-1]。

如果t = 1,那么还要再加上N mod (10^(n-1))的结果,如果t>1,加上10^(n-1)的值即可。

代码如下:

#include<iostream>
using namespace std;

int main()
{
    unsigned long n;
    unsigned long part1,part2,ans,yu;
    unsigned long base = 1;
    unsigned int tmp;
    cin >> n;
    base = 1;        //用来表示10的几次方
    ans = 0;        //用来存储最终的结果
    yu = n%10;        //用来表示N mod (10^(n-1))的结果,即余数
    part1 = 1;        //表示part1
    if (yu >= 1) ans = 1;
    part2 = ans;     //表示part2
    n = n/10;
    while (n!=0){
        tmp = n % 10;
        base = base*10;
        ans = tmp*part1 + part2;
        if(tmp == 1) ans = ans + yu + 1;
        else if (tmp > 1) ans = ans + base;
        part1 = part1*10 + base;
        part2 = ans;
        n = n/10;
        yu = tmp*base + yu;
    }
    cout << ans<<endl;
    return 0;
}

 

posted on 2013-02-28 16:32  civi  阅读(139)  评论(0)    收藏  举报

导航