统计0到n之间1的个数

问题描写叙述

给定一个十进制整数N,求出从1到N的全部整数中出现”1”的个数。

比如:N=2时 1,2出现了1个 “1” 。

N=12时 1,2,3,4,5,6,7,8,9,10,11,12。

出现了5个“1”。

解题思路

1位数的情况:

在解法二中已经分析过,大于等于1的时候。有1个,小于1就没有。

2位数的情况:

N=13,个位数出现的1的次数为2。分别为1和11,十位数出现1的次数为4,分别为10,11,12,13,所以f(N) = 2+4。

N=23,个位数出现的1的次数为3,分别为1,11,21,十位数出现1的次数为10,分别为10~19,f(N)=3+10。

由此我们发现。个位数出现1的次数不仅和个位数有关。和十位数也有关,假设个位数大于等于1,则个位数出现1的次数为十位数的数字加1;假设个位数为0。个位数出现1的次数等于十位数数字。而十位数上出现1的次数也不仅和十位数相关,也和个位数相关:假设十位数字等于1,则十位数上出现1的次数为个位数的数字加1,假如十位数大于1,则十位数上出现1的次数为10。

3位数的情况:

N=123

个位出现1的个数为13:1,11,21,…。91,101,111,121

十位出现1的个数为20:10~19,110~119

百位出现1的个数为24:100~123

我们能够继续分析4位数,5位数,推导出以下普通情况:

假设N,我们要计算百位上出现1的次数。将由三部分决定:百位上的数字,百位以上的数字。百位一下的数字。

假设百位上的数字为0,则百位上出现1的次数仅由更高位决定,比方12013,百位出现1的情况为100~199,1100~1199,2100~2199,…,11100~11199,共1200个。等于更高位数字乘以当前位数。即12 * 100。

假设百位上的数字大于1,则百位上出现1的次数仅由更高位决定。比方12213,百位出现1的情况为100~199,1100~1199,2100~2199。…,11100~11199。12100~12199共1300个。

等于更高位数字加1乘以当前位数,即(12 + 1)*100。

假设百位上的数字为1,则百位上出现1的次数不仅受更高位影响,还受低位影响。比如12113,受高位影响出现1的情况:100~199,1100~1199,2100~2199。…,11100~11199,共1200个,但它还受低位影响,出现1的情况是12100~12113,共114个,等于低位数字113+1。

实现代码

#include <iostream>
#include <cstring>
using namespace std;

int countOne(int n)
{
    int current = 0;
    int before = 0;
    int after = 0;
    int i = 1;
    int count = 0;
    while (n / i != 0)
    {
        current = n / i % 10;
        before = n / (i * 10);
        after = n - (n / i) * i;
        if (current > 1)
        {
            count += (before + 1) * i;
        }
        else if (current == 0)
        {
            count += before * i;
        }
        else if (current == 1)
        {
            count += before * i + after + 1;
        }

        i *= 10;
    }

    return count;
}

int main()
{
    int n;
    while (cin>>n)
    {
        cout<<countOne(n)<<endl;
    }

    return 0;
}
时间: 2024-07-30 13:39:17

统计0到n之间1的个数的相关文章

【剑指offer】统计0到n之间1的个数[数学]

问题描述 给定一个十进制整数N,求出从1到N的所有整数中出现"1"的个数. 例如:N=2时 1,2出现了1个 "1" . N=12时 1,2,3,4,5,6,7,8,9,10,11,12.出现了5个"1". //暴力求解 long CountOnes(long n) { int i,j;//循环变量 int ncount=0;//计数 for (i=1; i<=n; i++) { j=i; while(j!=0) { if (j%10==1

统计0到n之间1的个数[数学,动态规划dp](经典,详解)

问题描述 给定一个十进制整数N,求出从1到N的所有整数中出现”1”的个数.  例如:N=2时 1,2出现了1个 “1” . N=12时 1,2,3,4,5,6,7,8,9,10,11,12.出现了5个“1”. 方法一 暴力求解 最直接的方法就是从1开始遍历到N,将其中每一个数中含有“1”的个数加起来,就得到了问题的解. 下面给出代码: 1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 int

随机生成0到n之间的m个数

分析:使用knuth算法: void PutRand(int n,int m) { srand(time(NULL)); for (int i=0;i<n;i++) { if(rand()%(n-i)<m) { cout<<i<<endl; m--; } } } 证明: 1.当i=0时,则生成的随机数是0,1,2...n-1之间的数,共n个:这是0被选到的概率为m/n. 2.当i=1时,生成的随机数是0,1,2...n-2之间的数,共n-1个:假设上次0被选到,那么这次

UPC 2224 Boring Counting (离线线段树,统计区间[l,r]之间大小在[A,B]中的数的个数)

题目链接:http://acm.upc.edu.cn/problem.php?id=2224 题意:给出n个数pi,和m个查询,每个查询给出l,r,a,b,让你求在区间l~r之间的pi的个数(A<=pi<=B,l<=i<=r). 参考链接:http://www.cnblogs.com/zj62/p/3558967.html #include <iostream> #include <cstdio> #include <cstring> #incl

poj 3286 统计0的个数

1 #include <iostream> 2 3 using namespace std; 4 long long p; 5 long long a[20]; 6 long long solve(long long n){ 7 long long left,m,sum =0; 8 for(int i=1;i<12;i++){ 9 left = n/a[i]-1; 10 sum += left*a[i-1]; 11 m = (n%a[i]-n%a[i-1])/a[i-1]; 12 if(

Help Tomisu UVA - 11440 难推导+欧拉函数,给定正整数N和M, 统计2和N!之间有多少个整数x满足,x的所有素因子都大于M (2&lt;=N&lt;=1e7, 1&lt;=M&lt;=N, N-M&lt;=1E5) 输出答案除以1e8+7的余数。

/** 题目:Help Tomisu UVA - 11440 链接:https://vjudge.net/problem/UVA-11440 题意:给定正整数N和M, 统计2和N!之间有多少个整数x满足,x的所有素因子都大于M (2<=N<=1e7, 1<=M<=N, N-M<=1E5) 输出答案除以1e8+7的余数. 思路: lrjP338 由于x的所有素因子都>M:那么x与M!互质. 根据最大公约数的性质,对于x>y,x与y互质,那么x%y与y也互质. 由于N

统计一个字符串中的单词的个数,并打印各个单词

/*测试数据:Shen zhen is a beautiful city!*/ /*运行结果:Word:6 Shen zhen is a beautiful city!*/ #include<stdio.h> #define SIZE 1000 void wordCount(char *str) { int count = 0, flag = 0; char *p = str; while (*p != '\0'){ while (*p == 32){ if (*(p + 1) == 0){/

蓝桥--危险系数(求两点之间的割点个数)

历届试题 危险系数 时间限制:1.0s   内存限制:256.0MB 问题描述 抗日战争时期,冀中平原的地道战曾发挥重要作用. 地道的多个站点间有通道连接,形成了庞大的网络.但也有隐患,当敌人发现了某个站点后,其它站点间可能因此会失去联系. 我们来定义一个危险系数DF(x,y): 对于两个站点x和y (x != y), 如果能找到一个站点z,当z被敌人破坏后,x和y不连通,那么我们称z为关于x,y的关键点.相应的,对于任意一对站点x和y,危险系数DF(x,y)就表示为这两点之间的关键点个数. 本

C语言:求出0~999之间的所有“水仙花数”并输出

#include <stdio.h> int main() {  int num,unit,ten,hundred;  int i=0;  printf("水仙花数:\n");  for(num=100;num<=999;num++)  {   hundred=num/100;   ten=(num-hundred*100)/10;   unit=num-hundred*100-ten*10;    if(num==hundred*hundred*hundred+te