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 题意 一个正整数是 漂亮数 ,当且仅当它能够被自身的各非零数字整除.我们不必与之争辩,只需计算给定范围中有多少个漂亮数 ...
随机推荐
- iOS 多线程的简单理解(3)执行方式 + 执行对列 的组合
通过对前面两偏线程理解的总结,自己对线程的理解也逐渐加深,梳理的清晰起来…… 通常在使用线程 的时候,都是要用到 执行对列,执行方式,执行任务, 现在开始新一轮的深入 3. 1. 1 同步 + 串行 ...
- PHP实现单点登录最简单的方法
PHP实现单点登录最简单的方法 用户在A登录 存入登录状态 登录B站(A的识别要传入B) 获取A的登录状态
- [CF1005F]Berland and the Shortest Paths_最短路树_堆优化dij
Berland and the Shortest Paths 题目链接:https://www.codeforces.com/contest/1005/problem/F 数据范围:略. 题解: 太鬼 ...
- IDEA 的操作与使用
idea 设置syso File –> Setting –> Editor –> Live Templates debug 调试: F7 在 Debug 模式下,进入下一步,如果当前 ...
- [转帖]Epoll和IOCP的比较
Epoll和IOCP的比较 https://yq.aliyun.com/articles/53621/ kryptosx 2016-05-27 23:32:51 浏览6181 原来整理过一个& ...
- IdentityServer4 学习三
ClientCredentials客户端类型实现 客户端应用向IdentityServer请求AccessToken,IdentityServer验证通过把AccessToken返回给客户端应用,客户 ...
- Jmeter-后置处理器--json提取器
Token提取: 将token放入全局变量: 将token值设为全局变量,${__setProperty(newtoken,${token},)} 添加请求头部管理器作为全局使用,将变量token使 ...
- JAVA堆,栈的区别,用AarrayList、LinkedList自定义栈
大家都知道java模拟机在运行时要开辟空间所以它有特定的五个内存划分: 1.寄存器: 2.本地方法区: 3.方法区: 4.栈内存: 5.堆内存: 但是我们今天来注重讲一下栈和堆 ...
- jdk8新特性--函数式接口的使用
函数式接口的概念: 函数式接口的格式: 示例: 函数式接口的使用: 简化lambda表达式:
- Qt:用 __thread 关键字让每个线程有自己的全局变量
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/wsj18808050/article/d ...