poj 3286 求一个区间十进制数的0的个数的和(附:0~N十进制表示1的个数和)

本文介绍了一种高效算法,用于计算指定区间内所有数字中0和1出现的次数。通过分解数字并分析每一位对总数的贡献来解决此问题。适用于竞赛编程及算法优化场景。

题目大意:给定一个正数区间,要你求这个区间,包含区间两端点的十进制表示0的个数和

解题思路:假设区间[a, b],求0 ~ a - 1的这些数中0的个数,0~b的这些数中0的个数,然后把他们相减即为所求。

若a为0时,只要求0~b的0的个数就可以了。

求某个数,比如4位数abcd,只要求每位数对0的个数的贡献就行

比如3421,百位数对0的贡献有:1000,1001...1099,2000,2001,...,2099,3000~~~3099,即为3 * 100 = 300个

若是3021,百位数对0的贡献有:1000,1001....1099, 2000,2001,...,2099, 3000~~~3021,即为(3-1) * 100 + 21 + 1个

所以要求某位对0的贡献,当这一位为0时,贡献0的个数为(高位的数值 - 1) * 10^(低位的位数) + 低位数值  + 1个

当某位不为0时,贡献为 高位数值 * 10^(低位的位数) 


#include <iostream>
#include <cstdio>

using namespace std;

long long sum0(long long n);

int main()
{
   
    long long ans = 0;
    long long st, ed;
    while(true)
    {
        scanf("%lld %lld", &st, &ed);
        if(st == -1 && ed == -1)
            break;
        if(st == 0) 
        	printf("%lld\n", sum0(ed));
        else
        	printf("%lld\n", sum0(ed) - sum0(st - 1));
    }
    
    return 0;
}

long long sum0(long long n)
{
    if(n == 0)
        return 1;
    long long factor = 1;
    long long lowerNum = 0;
    long long curNum = 0;
    long long highNum = 0;
    long long num = 1;
    while(n / factor != 0)
	{
		lowerNum = n % factor;
		curNum = (n / factor) % 10;
		highNum = n / (factor * 10);
		switch(curNum)
		{
			case 0:
				num +=  (highNum - 1) * factor + lowerNum + 1; 
				break;
			default:
				num +=  highNum * factor; 
				break; 
		} 
		factor *= 10; 
	} 
    return num;
}


求0~~n的出现1的个数和的分析方法也是一样

比如12013,百位为0,贡献1的数为:100~199, 1100~1199,...,11100~11199。只有高位起作用,所以贡献个数为(11+1)* 10^2

若为12113时,百位为1贡献1的数为:100~199,1100~1199,...,11100~11199,12100~12113。高位和低位都起作用,贡献个数为(11+1)*10^2 + (13 + 1)

若为12313时,百位不为1和0,贡献数为100~199,1100~1199,...,11100~11199,12100~12199。只有高位起作用,贡献个数为(12+1)*10^2


代码实现为

long long sum1(long long n)
{
	if(n == 0)
		return 0;
		
	long long factor = 1;
    long long lowerNum = 0;
    long long curNum = 0;
    long long highNum = 0;
    long long num = 0;
    while(n / factor != 0)
	{
		lowerNum = n % factor;
		curNum = (n / factor) % 10;
		highNum = n / (factor * 10);
		switch(curNum)
		{
			case 0:
				num +=  highNum * factor; 
				break;
			case 1:
				num +=  highNum * factor + lowerNum + 1; 
				break; 
			default:
				num +=  (highNum + 1)* factor; 
				break; 
		} 
		factor *= 10; 
	} 
    return num; 
} 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值