How many 0's?

Description

A Benedict monk No.16 writes down the decimal representations of all natural numbers between and including m and nm ≤ n. How many 0's will he write down?

Input

Input consists of a sequence of lines. Each line contains two unsigned 32-bit integers m and nm ≤ n. The last line of input has the value of m negative and this line should not be processed.

Output

For each line of input print one line of output with one integer number giving the number of 0's written down by the monk.

Sample Input

10 11
100 200
0 500
1234567890 2345678901
0 4294967295
-1 -1

Sample Output

1
22
92
987654304
3825876150

  题意简单分析:给你两个数a和b,求从a手写到b,总共需要写多少个零(没有前置零)。先求出0到b需要的数num1,再求出0到a-1需要的数num2,用num1减去num2就是答案。

  问题可以递归分解成子问题,一步步简化处理;例如9287,拆分成五段来求零出现的次数——0-999,     1000-8999,9000-9199,    9200-9279,    9280-9287;

  chart数组,chart[i]表示从自然数0到i位(999..99)所写下的0 的个数(都是自然数不存在前置零)!上面的栗子中,第一段直接可以调用chart[]数组得出结果。(用chart[]省时,省步骤!第一次写没法推出chart数组,就暴力跑了一次;第二次,我觉得打表不是多稳,于是又花了两个小时坚持去推chart[]表,公式起始很简单,受cnt函数的影响,我起初一直仿照推下面cnt函数的方式去推——一直无果!后来,仔细跳出了推cnt的思路出来想想,起始就一行就够了!)

  dp数组,dp[i]表示从i位的(0...0)写到i位的(9...9)需要的0的个数,相当于给你i位数求这i位数的可能的所有组合(含前置零);接着上面的栗子中,第二段中,1000-8999可以看做1xxx,2xxx,3xxx,...,8xxx(xxx表示三位数的所有可能的组合个数);第三段,9000-9199, 可以看做90xx,91xx (xxx表示两位数的所有可能的组合个数);依次类推。

  fact数组,fact[i]数组存10的i 次幂= i位数的用0-9的全排列结果。

  建立上述三个数组以后,从高位向低位按照乘法和加法原则进行迭代求和即可。

#include<stdio.h>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
typedef long long ll;
#define eps 1e-10
ll dp[],fact[];
ll chart[];
ll arr[]={}; //由低位爬向高位 ll f3(ll a[],int i,int j){ //计算数组a[]第i到第j位构成的数字,如9086,f3(1,2)返回86
ll s=;
if(i<j)swap(i,j);
for(;i>=j;i--){
s=s*+a[i];
}
return s;
} void init()
{
fact[]=; //存10的次幂
for(int i=;i<=;i++)
fact[i]=fact[i-]*; dp[]=;dp[]=;
for(int i=;i<=;i++)
dp[i]=fact[i-]+*dp[i-]; //表示从i位的(0...0)写到i位的(99..9)需要的0的个数 chart[]=;
for(int i=;i<=;i++) //表示从0到共i位的(99..99)需要写的0的个数
chart[i]=chart[i-]+dp[i-]*; return ;
} ll cnt(int pos,int len) //返回自然数0 到 n的含零数
{
ll ans=;
if(pos==len&&len>){ //pos为最高位
ans+=(arr[pos]-)*dp[pos-]+ chart[pos-]+ cnt(pos-,len);
}
else if(pos==len&&len==){ //整个N只是个位数时
ans=;
}
else if(pos!=){ //当不是最高位和最后一位时
if(arr[pos]==){
ans+= f3(arr,,pos) +cnt(pos-,len)+; //1表示pos位0时
}
else{
ans+= arr[pos]*dp[pos-]+ cnt(pos-,len)+fact[pos-]; //fact[i-1]表示该为为0时
}
}
else{ //最后一位时
if(arr[pos]==){
ans+=;
}
else{
ans+=; //最后一位的0
}
}
// printf("pos=%d ans=%d\n",pos,ans);
return ans;
}
ll solve(ll n) //主要就是把n进行数位分离,然后调用cnt统计
{
if(n<)return (ll);
if(n==)return ;
ll ans=,len;
len=(ll)((int)log10(n*1.0)+);//计算n的位数 int i=;
while(n>)
{
arr[i++]=n%;n/=;
}
ans=cnt(len,len);
return ans;
} int main()
{
ll m,n;
init(); while(scanf("%lld%lld",&m,&n)!=EOF) //题意:m<=n
{
if(n==-&&m==-)break;
printf("%lld\n",solve(n)-solve(m-));
} return ;
}
//打表代码,大概等10秒钟可以跑完
/*void creat_chart(){
freopen("output.txt","w",stdout);
ll ss=0;int k=1;
for(ll i=0;i<=(ll)fact[9];i++){
ll j=i;
if(j==0)ss++;
while(j>0){
if(j%(ll)10==(ll)0)ss++;
j/=(ll)10;
}
if(i==fact[k]-1){
printf("0到%lld的含0数为: %lld\n",i,ss);k++;
}
}
printf("OK\n");
fclose(stdout);
}*/
/*得到chart【】表格 结果如下:
0到9的含0数为: 1
0到99的含0数为: 10
0到999的含0数为: 190
0到9999的含0数为: 2890
0到99999的含0数为: 38890
0到999999的含0数为: 488890
0到9999999的含0数为: 5888890
0到99999999的含0数为: 68888890
0到999999999的含0数为: 788888890
OK*/

用乘法和加法原则自己动手推推,很重要!反正你也看不懂!/斜眼笑

Poj-3286- How many 0's? - 【基础数位DP】的更多相关文章

  1. POJ 3286 How many 0's(数位DP模板)

    题目链接:http://poj.org/problem?id=3286 题目大意: 输入n,m,求[n,m]的所有数字中,0出现的总数是多少,前导零不算. 解题思路: 模板题,设dp[pos][num ...

  2. POJ 3286 How many 0's?(几多0?)

    POJ 3286 How many 0's?(几多0?) Time Limit: 1000MS   Memory Limit: 65536K [Description] [题目描述] A Benedi ...

  3. hdu2089:不要62(基础数位dp)

    题意:规定一个合法的号码不能含有4或者是连续的62 给定区间[n,m] 问此区间内合法的号码的个数 分析:数位dp dp[i][j]代表 最高位为 j 的 i 位数有多少个合法的 然后按题目规则进行转 ...

  4. POJ 3286 How many 0's?(数位DP)

    题目链接 终于过了,边界让我wa了好几次,猥琐的用AC代码对拍,很无奈,用非常麻烦的方法.写一下,估计以后再碰到,肯定看不懂这是写的什么了. 以前做过,统计1和2的,统计0比1和2麻烦多了,有前导0的 ...

  5. POJ 3286 How many 0's?

    题目链接 题意 :写下m到n之间所有的数,会写多少个0. 思路 :先算0到m的,再算0到n的,最后相减. 网上有位大神是这么推的,看下面.... 首先转化成求 [0, x] 中所有数中,含有的 0 的 ...

  6. POJ 3286 How many 0&#39;s?

    题目大意: 计算[m,n]之间全部数字有多少个零. 解题思路: 能够用[0,m)之间和[0,n]之间有多少个零然后作差. 规律是计算全部位置在到当前数时有多少个零. 以下是代码:   #include ...

  7. poj 3340 Barbara Bennett's Wild Numbers(数位DP)

    Barbara Bennett's Wild Numbers Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 3153   A ...

  8. 基础数位DP小结

    HDU 3555 Bomb dp[i][0] 表示含 i 位数的方案总和. sp[i][0] 表示对于位数为len 的 num 在区间[ 10^(i-1) , num/(10^(len-i)) ] 内 ...

  9. 「kuangbin带你飞」专题十五 数位DP

    传送门 A.CodeForces - 55D Beautiful numbers 题意 一个正整数是 漂亮数 ,当且仅当它能够被自身的各非零数字整除.我们不必与之争辩,只需计算给定范围中有多少个漂亮数 ...

随机推荐

  1. pickle.load EOFError: Ran out of input

    错误原因:pickle.loads()的次数超过了pickle.dumps()的次数 https://www.cnblogs.com/cmnz/p/6986667.html

  2. CentOS 7/6系统升级内核版本到5.2.2

    由于公司服务器新业务需要,需要将CentOS 7系统的内核(3.10.0-229)进行升级. 关于内核版本的定义:版本性质:主分支ml(mainline),稳定版(stable),长期维护版lt(lo ...

  3. 基于TreeSoft实现mysql、oracle、sql server的数据同步

    一.为了解决数据同步汇聚,数据分发,数据转换,数据维护需求,TreeSoft推出了数据同步,数据处理等丰富功能 . TreeSoft作为中间传输载体负责连接各种数据源,为各种异构数据库之间架起沟通的桥 ...

  4. (7)Spring Boot web开发 --- servlet容器

    文章目录 配置嵌入式 Servlet 容器 注册 三大组件 使用其他 servlet 容器 使用外置的 `Servlet` 容器 配置嵌入式 Servlet 容器 Spirng Boot 默认使用自带 ...

  5. xsy 2412【BZOJ4569】【Scoi2016】萌萌哒

    Description Description 一个长度为n的大数,用S1S2S3...Sn表示,其中Si表示数的第i位,S1是数的最高位,告诉你一些限制条件,每个条件表示为四个数,l1,r1,l2, ...

  6. Python中的动态属性与描述符

    动态属性与属性描述符 属性描述符是什么?   在解释属性查找顺序之前我们需要了解Python中的属性描述符,属性描述符作为其他类对象的属性而存在,实现了特殊方法中的get.set.delete中的一种 ...

  7. session和cookie有什么区别?

    1.存储位置不同 cookie的数据信息存放在客户端浏览器上. session的数据信息存放在服务器上. 2.存储容量不同 单个cookie保存的数据<=4KB,一个站点最多保存20个Cooki ...

  8. Emit用法

    [转自]https://blog.csdn.net/xiaouncle/article/details/52890037 本人是从0开始学习Emit的,在学习过程中比较困扰我的就是有很多指令不理解.不 ...

  9. MLP神经网络实例--手写识别

    1.导入MNIST数据集 直接使用fetch_mldata会报错,错误信息是python3.7把fetch_mldata方法移除了,所以需要单独下载数据集从这个网站上下载数据集: https://gi ...

  10. 快开宝PDA开单器出入库扫码:让批发零售变得更简单

    快开宝PDA开单器出现前 批发商户是这样开单和管理的 ★员工痛苦:需要记客户.价格.库存等等,应对报错价.错漏单.盘错货等各种状况. ★老板麻烦:每天要守店.对单.核账,经常因错漏单.库存乱.积压货. ...