- 时间限制:1秒空间限制:32768K
- 通过比例:21.59%
- 最佳记录:0 ms|8460K
题目描述
NowCoder总是力争上游,凡事都要拿第一,所以他对“1”这个数情有独钟。爱屋及乌,他也很喜欢包含1的数,例如10、11、12……。你能帮他统计一下有多少个包含1的正整数吗?
PS: 最佳纪录0秒的方法,我还不知道。。。应该可以按照这个思路继续优化吧,可能可以采用递归试试,改天有空再试试
输入描述:
输入有多组数据,每组数据包含一个正整数n,(1≤n≤2147483647)。
输出描述:
对应每组输入,输出从1到n(包含1和n)之间包含数字1的正整数的个数。
输入例子:
1 9 10 20
输出例子:
1 1 2 11
简要分析:
此题从题目意思来看非常简单,第一想法就是暴力求解的方法,去计算每一个数是否有包含1。但是这样的话很多情况就重复计算了。
例如,100包含1,101也包含1,这两个数的最高位都包含1,也就是说,若最高位包含1,则无论其余位是否包含1,则该数都是包含1。
因此若采用暴力求解,当n超过100 000 000的时候,运行时间就不符合要求了。
我的解决思路就是,把一个数拆成两半,若前一半包含1,则后一半无论是什么值这个数都是包含1的。若前一半不包含1,则需计算后一半包含1的个数。我以N = 100 000为界限,暴力求解在这个数值内是可以符合要求的。
实现代码如下:
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
void solver1(int n);
void solver2(int n);
bool is_containOne(int n);
int countOne(int n);
int countOne(int n)
{
int cnt = 0;
for (int i = 1; i <= n; i++)
{
if (is_containOne(i))
{
//判断是否包含1,true则增1
cnt++;
}
}
return cnt;
}
bool is_containOne(int n)
{
while (n)
{
if (n%10 == 1)
{
//判断n这个数里是否包含1,是,则返回true
return true;
}
n = n/10;
}
return false;
}
void solver2(int n)
{
long long cnt = 0;
int N = 100000;
if (n <= N)
{
//小于N的数用暴力解法即可
solver1(n);
}else
{
//大于N的数采用分割的方式解决
/*
将一个数分成大于N的部分和小于N的部分,例如2147000,则分为21和47000这两部分
则此时就可以分为大于Nde部分包含1的个数与不包含1的个数
通过分别求出21和47000的包含1个数来计算整个数包含1的个数
*/
int x = n/N;
int cntx = countOne(x);//大于N的部分包含1的个数
int cntN = countOne(N);
int y = n%N;
int cnty = countOne(y);//小于N的部分包含1的个数
if (is_containOne(x))
{
/*
当大于N的部分包含1,0~N的部分包含1的个数为cntN, N+1~x*N的部分包含1的个数为(cntx-1)*N
N+1~x*N的部分不包含1的个数为(x-cntx)*(cntN-1),x*N~x*N+y的部分包含1的个数为y
*/
cnt = (cntx-1)*N + (x-cntx)*(cntN-1) + cntN;
cnt += y;
}else
{
/*
当大于N的部分不包含1,此时易知x>1,则N+1~x*N的部分包含1的个数为cntx*N,
N+1~x*N的部分不包含1的个数为(x-cntx)*(cntN-1),x*N~x*N+y的部分包含1的个数为cnty
*/
cnt = cntx*N + (x-cntx)*(cntN-1);
cnt += cnty;
}
// printf("cntx = %d, cntN = %d, cnty = %d\n", cntx, cntN, cnty);
printf("%ld\n", cnt);
}
return;
}
void solver1(int n)
{
//暴力求解方法
int cnt = countOne(n);
printf("%d\n", cnt);
return;
}
int main()
{
int n;
// printf("%d", is_containOne(100001));
while (scanf("%d", &n) == 1)
{
solver2(n);
// solver1(n);
}
return 0;
}
PS: 最佳纪录0秒的方法,我还不知道。。。应该可以按照这个思路继续优化吧,可能可以采用递归试试,改天有空再试试
本文介绍了一种高效算法,用于统计指定范围内包含数字1的正整数个数。通过对数值进行拆分并利用递归思想减少重复计算,实现了在大范围内的快速求解。

1098

被折叠的 条评论
为什么被折叠?



