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. filebeat输出到kafka

    # cat filebeat.yml filebeat.inputs: - type: log enabled: true tail_files: true paths: - /data/www.ex ...

  2. unix系统简明教程 命令

    who                                 显示电脑用户信息 liu :0 Oct 6 13:17 (:0)liu pts/2 Oct 6 13:22 (:0) who a ...

  3. eNSP模拟器OSPF单区域配置

    实验拓扑图如下 下一步对终端设备与路由器的端口进行基本的ip设置 配置完成后要注意检查是否有小错误,不然会对后面的测试带来麻烦.在进行基础配置的时候一定要细心细心细心. 下一步我们就要进行OSPF的配 ...

  4. mysql 库、表、数据的增删改

    数据库定义 语法形式 (1)创建数据库 create database [if not exists ] 数据库名 [charset 字符集] [collate 字符排序规则]; if not exi ...

  5. 使用派生镜像(qcow2)

    当创建的虚拟机越来越多,并且你发现好多虚拟机都是同一个操作系统,它们的区别就是安装的软件不大一样,那么你肯定会希望把他们公共的部分提取出来,只保存那些与公共部分不同的东西,这样镜像大小下去了,空间变多 ...

  6. Action<T>和Func<T>委托事例

    Action<T>和Func<T>委托事例 using System; //除了为每个参数和返回类型定义一个新委托类型之外,还可以使用Action<T>和Func& ...

  7. C++中数组占用的内存计算

    在C++中int类型每个空间是4个字节,long long int 是8个字节,而bool类型是1个字节 所以一般能用bool就别用int,节约空间 数组占用内存的计算 a[1001][1001]的空 ...

  8. BJFU-208-基于顺序存储结构的图书信息表的最贵图书的查找

    #include<stdio.h> #include<stdlib.h> #define MAX 1000 typedef struct{ double no; char na ...

  9. 在被调用函数中获取资源及C++中的引用

    #include <iostream> using namespace std; struct Teacher{ char name[64]; int age; }; //在被调用函数 获 ...

  10. docker 实践四:数据管理

    这篇是关于 docker 的数据管理. 注:环境为 CentOS7,docker 19.03. 一般容器中管理数据主要有两种方式: 数据卷(Data Volumes):容器内数据直接映射到本地主机环境 ...