TOJ 4148 number 0

题目链接:http://acm.tju.edu.cn/toj/showp4148.html

题意是算出一个数小于等于它的所有数中0的个数。

首先上来第一反应是暴力,毕竟每一个数的答案都是死的,不会随着变量变化,所以自己写了一个10^8的暴力,抱着一秒一亿次运算可能能卡过的侥幸心里,想试一试,不过结果自己运行都要差不多10秒才能跑出来……

那么我们只能尝试去找寻规律之类的做法,那么我们可以考虑每一位上的关系(也就是所谓的数位DP)。

我们从第一位开始考虑每一位出现0的个数的情况,举个例子,我们来讨论1234这个数不超过它出现的0的个数。

从个位开始,如果这位是0的话,那么前面的三位可以从1~123都可以,所以个位就有123个0;

十位,如果这位是0的话,那么前面的可以从1~12,后面的可以从0~9,所以十位就有120个0;

百位,如果这位是0的话,那么前面的只能排1,后面的可以从0~99,所以百位就有100个0;

所以1234总共就有123+120+100 = 323个0;

但是我们刚刚讨论的情况不够特殊,因为不含0,但是实际讨论的时候如果有0的话我们要特殊讨论一下,再举个例子把刚刚的1234换成1204。

个位:1~120,120个0;

十位:前面是1~12,后面是0~9,这么看来应该是120个,但是当前面的是120的时候,如果我们后面的比4大的话,那么我们枚举的这个实际就超过了1204,我们只能枚举小于1204的,所以十位应该是120 - (10-4-1) = 115.

百位:前面只能是1,后面是0~99,100个0:

所以总共就是120+115+100 = 335个0.

那么从刚刚两个例子我们可以看出来,在枚举的过程中,如果枚举的那一位是非0的话,那么这一位的0的个数就是前面的数*后面的数,如果这一位是0的话,那么我们还要讨论枚举出来的比这个大的情况,这一位0的个数是前面的数*后面的数 - 枚举多出来的数。

#include <cstdio>
long Count(long n)
{
    long count = 0;
    long i = 1;
    long current = 0, after = 0, before = 0;
    while((n / i) != 0)
	{
        current = (n / i) % 10;
        before = n / (i * 10);
        after = n - (n / i) * i;
        if(current > 0)
            count = count + before * i;
        else if(current == 0)
            count = count + before * i - (i-after-1);
        i = i * 10;
    }
    return count;
}
int main()
{
	int n,T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d", &n);
		int x = Count(n);
		printf("%d\n",x);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值