【编程马拉松】【004-包含一】

【编程马拉松算法目录>>>】


【004-包含一】【工程下载>>>】


1 题目描述


  NowCoder总是力争上游,凡事都要拿第一,所以他对“1”这个数情有独钟。爱屋及乌,他也很喜欢包含1的数,例如10、11、12……。你能帮他统计一下有多少个包含1的正整数吗?

1.1 输入描述:


  输入有多组数据,每组数据包含一个正整数n,(1≤n≤2147483647)。

1.2 输出描述:


  对应每组输入,输出从1到n(包含1和n)之间包含数字1的正整数的个数。

1.3 输入例子:


1
9
10
20

1.4 输出例子:


1
1
2
11

2 解题思路


  假设有数字 X(n)=xnxn1x2x1x0 xi 上的权重是 10i
  先考虑 09n9n1929190 ,中出现1的数字个数,假设它是 P(n) ,它由三部分组成:
  - 09n1929190 ,含有1的数字数目是 P(n1)
  - 1n0n19291901n9n1929190 ,含有1的数字数目是 10n1
  - 1<ji<xi ji0i1020100 ji9i1929190 中含有1的数字数目是 P(n1) ji 可以取8个数字。
  所以 P(n1)=P(n1)+10n1+8P(n1)=9P(n1)+10n1 ,又 n=0 时, P(n)=1 ,综上有:

P(n)={19P(n1)+10n1n=0n>0

  再考虑 X(n) ,从右到左处理 X(n) 上的每一位,假设当前处理第i位。则要分三种情况:
  第一种: xi=0 ,则 xixi1x2x1x0 xi1x2x1x0 含有1的数字个数相同,则 F(i)=F(i1)
  第二种: xi=1 ,则 xixi1x2x1x0 包含1的由两部分组成:
    - 09i1929190 中含有1的数字数,为 P(i1)
    - xi0i1020100xixi1x2x1x0 中含有1的数字,为 X(i1)+1
  则有 F(i)=P(i1)+X(i1)+1
  第三种: xi>1 ,则 xixi1x2x1x0 包含1的由四部分组成:
    - 0xi1x2x1x0 中含有1的数字数,为 P(i1)
    - 1i0i10201001i9i1929190 中含有1的数字数,为 10i1
    - 1<ji<xi ji0i1020100ji9i1929190 中含有1的数字数,为 P(i1) 。j_i可以取 xi2
    - xi0i1020100 xixi1x2x1x0 中含有1的数字,为 F(i1)
  则有 F(i1)=P(i1)+10i1+(xi2)P(i1)+F(i1)=(xi1)P(i1)+10i1+F(i1)
  综合有:
  当 n=0 时, X(n)=x0

F(n)=1

  当 n>0 时, X(n)=xnxn1x2x1x0

F(n)=F(n1)P(n1)+X(n1)+1(xn1)P(n1)+10n1+F(n1)xn=0xn=1xn>1

3 算法实现


import java.util.Scanner;

/**
 * Author: 王俊超
 * Time: 2016-05-06 17:52
 * CSDN: http://blog.csdn.net/derrantcm
 * Github: https://github.com/Wang-Jun-Chao
 * Declaration: All Rights Reserved !!!
 */
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
//        Scanner scanner = new Scanner(Main.class.getClassLoader().getResourceAsStream("data.txt"));
        while (scanner.hasNext()) {
            int n = scanner.nextInt();
            System.out.println(countOne(n));
        }

        scanner.close();
    }

    /**
     * 【方法一】
     * 计算[1-n]中包含数字1的数字个数
     *
     * @param n 最在范围
     * @return 包含数字1的数字个数
     */
    private static int countOne(int n) {

        int countedN = 0;
        int result = 0;

        // 从右向左分析n的每一位;for循环中:i 表示分析到了哪一位,i=1表示个位,i=10表示十位,以此类推;
        // onesPerI 表示从0到i-1含有1的数的个数,0,1,19 ...;
        // cur 是目前分析的那一位的数值;
        // 举个例子: f(m,n) 表示从m到n,含有1的数字的个数。
        // f(1,500) = f(1, 99)+f(100, 199)+f(200, 299)+(300, 399)+f(400, 499)
        // f(1, 99) = f(200, 299) = f(300, 399) = f(400, 499)
        // f(100, 199) = 100
        for (int i = 1, onesPerI = 0, cur; n != 0; onesPerI = onesPerI * 9 + i, i *= 10, n /= 10) {

            // 当前数位的数值
            cur = n % 10;

            if (cur == 0) {
                continue;
            } else if (cur == 1) {
                // onesPerI表示[1, i-1]含有1的个数,countedN表示比
                result = onesPerI + countedN + 1;
            } else {
                result += (cur - 1) * onesPerI + i;
            }

            // 表示比第i位以及比第i位低的各位的数值,比如abcdef,现在处理万位,那么countN就是bcdef
            countedN += cur * i;

        }

        return result;
    }

}

4 测试结果


这里写图片描述

5 其它信息


因为markddow不好编辑,因此将文档的图片上传以供阅读。Pdf和Word文档可以在Github上进行【下载>>>】

这里写图片描述
这里写图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
马拉松编程题目是一种挑战性的编程竞赛,要求参赛者在有限的时间内解决一系列复杂的编程问题。这些题目旨在测试参赛者的编程技能、算法思维和解决问题的能力。 在NOI(全国青少年信息学奥林匹克竞赛)中,编程马拉松题目非常有名。参赛者通常需要在一天内完成多个编程问题,每个问题的难度和复杂性都不同。这些题目可能涉及算法数据结构、动态规划、图论等各种领域。 参赛者在比赛开始时会收到一份题目清单,然后他们需要逐个解决各个问题。解题速度和准确性是评判参赛者成绩的重要指标。因为时间有限,参赛者需要在压力下迅速找到问题的解决方法,并编写高效的代码。 编程马拉松不仅考察了参赛者的编程技能,也考验了他们的团队合作能力。许多编程马拉松都是以小组形式进行,每个小组的成员需要相互配合,合理分工,共同完成任务。 参加编程马拉松有助于提升参赛者的编程能力和解决问题的能力。通过面临各种难题和时间限制,参赛者能够锻炼自己的思维能力和解决问题的方法。此外,参加编程马拉松还能与其他优秀的编程爱好者交流、学习,扩展自己的知识和视野。 总之,编程马拉松是一种激动人心的编程竞赛,可以帮助参赛者提升编程能力和解决问题的能力。这种比赛不仅考察了编程技能,还培养了团队合作和应对压力的能力,对于对编程有兴趣的人来说是一次难得的学习和锻炼机会。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值