PAT 甲级 1049(30 分)

PAT 甲级 1049(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

思路

也即计算小于等于N的数中含有1的个数。这题我想到了动态规划,以 9 , 99 , 999 , 9999 , . . . . . 9, 99, 999, 9999,..... 9,99,999,9999,.....为界划分数据,即 i = 0 i = 0 i=0时,以9为界,此时显而易见 c [ 0 ] = 1 c[0] = 1 c[0]=1,当 i = 1 i = 1 i=1时,以99为界,这时需要分析一下,在 [ 0 , 9 ] [0, 9] [0,9]范围内,1的个数为1,也即 c [ 0 ] c[0] c[0],而在 [ 10 , 19 ] [10, 19] [10,19]的范围内可以看见十位都有1,而个位的1的个数刚好是 c [ 0 ] c[0] c[0],所以1的的个数是 10 + c [ i − 1 ] 10 + c[i - 1] 10+c[i1],在 [ 20 , 99 ] [20, 99] [20,99]的范围内,只能是个位上有 c [ 0 ] c[0] c[0]个1,所以共有 8 ∗ c [ 0 ] 8 * c[0] 8c[0]个。故 c [ 1 ] = c [ 0 ] + c [ 0 ] + 10 + 8 ∗ c [ 0 ] c[1] = c[0]+c[0]+10+ 8*c[0] c[1]=c[0]+c[0]+10+8c[0]。以999为界的一样的分析,在 [ 0 , 99 ] [0, 99] [0,99]范围内的1的个数为 c [ 1 ] c[1] c[1]个,在 [ 100 , 199 ] [100, 199] [100,199]范围内百位上都有1,共100个,十位个位的1的个数又恰好是 c [ 1 ] c[1] c[1]个,在 [ 200 , 999 ] [200, 999] [200,999]范围内只能在十位个位上出现1,所以刚好又是 c [ 1 ] ∗ 8 c[1]*8 c[1]8个,故总的个数为 c [ 2 ] = c [ 1 ] + 100 + c [ 1 ] + c [ 1 ] ∗ 8 c[2] = c[1]+100+c[1]+c[1]*8 c[2]=c[1]+100+c[1]+c[1]8。故可以得出当 i > 0 i > 0 i>0时, c [ i ] = 10 ∗ c [ i − 1 ] + 1 0 i c[i] = 10*c[i - 1] + 10^i c[i]=10c[i1]+10i

而对于一个随机的数x,找出它的上界,例如15的上界是10, 345的上界是100。找到之后在低于上界的部分由 c [ i ] c[i] c[i]数组就能得到。而高于上界的部分则按照刚刚的规则再做一遍,直到数小于10为止。若最后数大于1,那么还需要再额外加一个。

AC代码

#include <iostream>

using namespace std;

int main() {
    int n;
    cin >> n;
    int count = 0;
    int tmp = 1;
    int c[9];
    c[0] = 1;
    int x = 1;
    //计算c数组
    for (int j = 1; j < 9; j++) {
        x = x * 10;
        c[j] = c[j - 1] * 10 + x;
    }
    //得到上界,由于数小于2^30,则完全可以达到10^9(通过提交代码测出测试点6应该是大于10^9次方的),10^10是越界的,故需要处理一下越界的数
    int i = 0;
    for (i = 0; tmp <= n && i < 9; i++) {
        tmp *= 10;
    }
    if (i < 9 || (i == 9 && n < tmp)) {
        tmp = tmp / 10;
        i--;
    }
    //循环处理
    while (n >= 10) {
        int a = n / tmp;
        n = n - tmp * a;
        if (a == 1) {//如果数是以1开头
            count += (c[i - 1] + n + 1);
        }
        else if(a > 1){//如果数的开头大于1
            count += (c[i - 1] * 2 + tmp + (a - 2) * c[i - 1]);
        }
        tmp = tmp / 10;
        i--;
    }
    if (n >= 1) {
        count++;
    }
    cout << count << endl;

	system("pause");
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值