Poj-3286- How many 0's? - 【基础数位DP】
How many 0's?
Description
A Benedict monk No.16 writes down the decimal representations of all natural numbers between and including m and n, m ≤ 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 n, m ≤ 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】的更多相关文章
- POJ 3286 How many 0's(数位DP模板)
题目链接:http://poj.org/problem?id=3286 题目大意: 输入n,m,求[n,m]的所有数字中,0出现的总数是多少,前导零不算. 解题思路: 模板题,设dp[pos][num ...
- POJ 3286 How many 0's?(几多0?)
POJ 3286 How many 0's?(几多0?) Time Limit: 1000MS Memory Limit: 65536K [Description] [题目描述] A Benedi ...
- hdu2089:不要62(基础数位dp)
题意:规定一个合法的号码不能含有4或者是连续的62 给定区间[n,m] 问此区间内合法的号码的个数 分析:数位dp dp[i][j]代表 最高位为 j 的 i 位数有多少个合法的 然后按题目规则进行转 ...
- POJ 3286 How many 0's?(数位DP)
题目链接 终于过了,边界让我wa了好几次,猥琐的用AC代码对拍,很无奈,用非常麻烦的方法.写一下,估计以后再碰到,肯定看不懂这是写的什么了. 以前做过,统计1和2的,统计0比1和2麻烦多了,有前导0的 ...
- POJ 3286 How many 0's?
题目链接 题意 :写下m到n之间所有的数,会写多少个0. 思路 :先算0到m的,再算0到n的,最后相减. 网上有位大神是这么推的,看下面.... 首先转化成求 [0, x] 中所有数中,含有的 0 的 ...
- POJ 3286 How many 0's?
题目大意: 计算[m,n]之间全部数字有多少个零. 解题思路: 能够用[0,m)之间和[0,n]之间有多少个零然后作差. 规律是计算全部位置在到当前数时有多少个零. 以下是代码: #include ...
- poj 3340 Barbara Bennett's Wild Numbers(数位DP)
Barbara Bennett's Wild Numbers Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 3153 A ...
- 基础数位DP小结
HDU 3555 Bomb dp[i][0] 表示含 i 位数的方案总和. sp[i][0] 表示对于位数为len 的 num 在区间[ 10^(i-1) , num/(10^(len-i)) ] 内 ...
- 「kuangbin带你飞」专题十五 数位DP
传送门 A.CodeForces - 55D Beautiful numbers 题意 一个正整数是 漂亮数 ,当且仅当它能够被自身的各非零数字整除.我们不必与之争辩,只需计算给定范围中有多少个漂亮数 ...
随机推荐
- Charles 抓包配置
本文参考:charles 抓包配置 proxy setting (代理设置) 设置的主界面如下: 动态端口 启用动态端口选项来监听动态端口,每次查询启动时选择.这样可以避免与计算机上可能运行的其他网络 ...
- 【GStreamer开发】GStreamer基础教程14——常用的element
目标 本教程给出了一系列开发中常用的element.它们包括大杂烩般的eleemnt(比如playbin2)以及一些调试时很有用的element. 简单来说,下面用gst-launch这个工具给出一个 ...
- AES加密、解密(linux、window加密解密效果一致,支持中文)
转自: http://sunfish.iteye.com/blog/2169158 import java.io.UnsupportedEncodingException; import java.s ...
- 树莓派上跑.NET的segment fault错误
答案:树莓派1和树莓派zero是不支持的,原因是.net需要arm v7 详情看这里 可以用 cat /proc/cpuinfo | grep 'model name' |uniq 看一下cpu
- WEB学习路线2019完整版(附视频教程+网盘下载地址)
WEB学习路线2019完整版(附视频教程+网盘下载地址).适合初学者的最新WEB前端学习路线汇总! 在当下来说web前端开发工程师可谓是高福利.高薪水的职业了.所以现在学习web前端开发的技术人员也是 ...
- xml文件中引用网址报红色如何解决
用了ideal的宝宝们一定遇到过配置文件网址报红的错误吧 其实解决很简单,就是网不好导致它没法补全,我们手动给他补全就好啦 复制报红的网址 点击File==>settings==>lang ...
- stm32f103的低功耗开启和关闭
stm32f103低功耗分为WFI等待中断和WFE等待事件,我只用到等待中断,这里没有细究. 待机模式最低功耗2uA,只有备份寄存器和待机电路供电,PLL,HSI,HSE断开,寄存器和SRAM复位,除 ...
- Nginx学习笔记(五):高级数据结构
目录 动态数组 单向链表 双端队列 红黑树 缓冲区 数据块链 键值对 动态数组 ngx_array_t 表示一块连续的内存,其中存放着数组元素,概念上和原始数组很接近 // 定义在 core/ng ...
- nodejs模块fs——文件操作api
// fs模块常用api // 读取文件 .写入文件 .追加文件. 拷贝文件 .删除文件 // 读取文件 // fs.readFile(path[, options], callback) // fs ...
- 2019牛客多校八 H. How Many Schemes (AC自动机,树链剖分)
大意: 给定树, 每条边有一个字符集合, 给定$m$个模式串, $q$个询问$(u,v)$, 对于路径$(u,v)$中的所有边, 每条边从对应字符集合中取一个字符, 得到一个串$s$, 求$s$至少包 ...