TOJ 4148 number 0
2016-06-29 18:33
369 查看
题目链接: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);
}
}
题意是算出一个数小于等于它的所有数中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);
}
}
相关文章推荐
- linux下tcp连接数
- 数据结构与算法究竟重要吗?
- c:forEach 标签中varStatus的用法
- linux不能ping通域名能ping通ip
- Mysql加载配置默认路径
- OJ解题报告 4976:硬币
- 大数据的仓库Hive原理(三)
- php 代码片段
- android NDK开发 静态/动态注册 jni
- Git的Patch功能
- Cookies 和 Session的区别
- 使用StoryBoard设置Scrollview的横向滚动不用一行代码
- JavaSE 基础 第38节 接口的实现
- jsp中常用操作字符串的el表达式
- Volley请求
- iOS UIWebview 分类 实现修改 javascript 两种提示框
- Opendap 4:Hyrax配置BES netcdf handler
- IOS策略模式与多态
- SQL语句练习题
- 随机生成任意十个整数,分别利用冒泡和选择按从小到大排列。