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. 【C/C++开发】C语言实现函数可变参数

    函数原型: int printf(const char *format[,argument]...)        返 回 值: 成功则返回实际输出的字符数,失败返回-1.  函数说明:        ...

  2. C++ 枚举定义

    我们在平常的编程中,时常需要为一些属性定义一组可以选择的值,比如文件打开的状态可能会有三种:输入 输出和追加 我们一般情况下记录这些状态是让每一个状态和一个常数相对应   比如 ; ; ; 这个方法虽 ...

  3. 网络I/O模型

    事件驱动模型 与传统编程模式不同,事件驱动程序在启动之后,就在那等待,等待什么呢?等待被事件触发.传统编程下也有“等待”的时候,比如在代码块D中,你定义了一个input(),需要用户输入数据.但这与下 ...

  4. Eclipse+TestNG搭建接口自动化测试框架

    一.环境安装 1.前提 安装好jdk 配置好Java环境变量 安装Eclips 这些网上都有,就不再详细介绍. 资源分享链接:http://pan.baidu.com/s/1v9Fw6 2.安装Tes ...

  5. Suspended Animation——《The Economist》阅读积累(考研英语二·2010 Reading Text 1)

    [知识小百科] Damien Hirst(达米恩●赫斯特):生于1965年,是新一代英国艺术家的主要代表人物之一.他主导了90年代英国艺术发展并享有很高的国际声誉.赫斯特在1986年9月就读于伦敦大学 ...

  6. Vue零碎总结

    1.Vue指令里的bind钩子是生成了vnode,但是将它插入/更新到浏览器dom树之前的操作,因此对于一些需要插入dom树后执行的操作它是不支持的,如el.focus()方法,这些要放在insert ...

  7. python爬虫-豆瓣电影的尝试

    一.背景介绍 1. 使用工具 Pycharm 2. 安装的第三方库 requests.BeautifulSoup 2.1 如何安装第三方库 File => Settings => Proj ...

  8. Git--远程仓库版本回退方法

    Git--远程仓库版本回退方法 1 简介 最近在使用git时遇到了远程分支需要版本回滚的情况,于是做了一下研究,写下这篇博客. 2 问题 如果提交了一个错误的版本,怎么回退版本? 如果提交了一个错误的 ...

  9. Java字符串定义及常用方法

    String.StringBuffer和StringBuilder   String修饰的是不可变的字符串,而StringBuffer和StringBuilder类的对象是可以被修改的.   Stri ...

  10. 解决Html页面缓存

    对于一个html页面,缓存分3部分,一个是页面内容,一个是css样式,一个是JS文件 CSS和JS文件缓存 <link rel="stylesheet" type=" ...