hdu2089(数位DP 递推形式)
不要62
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 25802 Accepted Submission(s): 8967
杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。
不吉利的数字为所有含有4或62的号码。例如:
62315 73418 88914
都属于不吉利号码。但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列。
你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多少辆新的士车上牌照了。
0 0
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
using namespace std ;
int dp[][];
//dp[len][0]代表不含4或62的个数
//dp[len][1]代表不含4或62的个数,首位为2
//dp[len][2]代表含4或62的个数
void init()
{
memset(dp,,sizeof(dp));
//dp[1][0]=9;
//dp[1][1]=1;
//dp[1][2]=1;
dp[][]=;
for(int len=;len<=;len++)
{
dp[len][]=dp[len-][]*-dp[len-][];
//在最高位加上除了4之外的9个数字,但是可能在2之前加了6
dp[len][]=dp[len-][];
//就是在原先不含4或62的最高位加2
dp[len][]=*dp[len-][]+dp[len-][]+dp[len-][];
//在已经有不吉利数字最高位加任意数字,或者在无吉利数字前加4,或者在2前面加4
}
} int solve(int x)
{
int s[],len=,xx=x;
while(x>)
{
s[++len]=x%;
x/=;
}
s[len+]=; //初始化前缀为0,0是没有任何影响的,后面一位可能会用到前面一位
// cout<<len<<endl;
int ans=,flag=;
for(int i=len;i>=;i--)
{
ans+=(s[i]*dp[i-][]);
if(flag) //如果前缀中有出现4或者62的话,那么后面的数就全加上
{
ans+=s[i]*dp[i-][];
} //只考虑以len位置为i的开头的数
if(!flag && s[i]>)
ans+=dp[i-][];
if(!flag && s[i]>)
ans+=dp[i-][];//因为是大于号,所以低一位可以完全枚举 //考虑前缀的影响
if(!flag && s[i+]== && s[i]>)
ans+=dp[i][];
if(s[i]== || (s[i+]== && s[i]==) )
{
flag=;
}
}
return xx-ans;
}
int main()
{
init() ;
int n,m ;
//
while(scanf("%d%d",&n,&m))
{
if(n== && m==)
break ;
// solve(101);
printf("%d\n",solve(m+)-solve(n)) ;//用[0,m]-[0,n)即可得到区间[n,m]
} return ;
}
dp[len][0]代表首位不为6,剩余长度为len,不含4和62的数的个数,
dp[len][1]代表首位为6,剩余长度为len,不含4和62的数的个数。
同样是枚举每个位置上的数,但是不同的是对于枚举当当前位置最大值的处理,dfs通过fp(代表是否是n的前缀)
这个参数只是用来告诉下一个状态是枚举到9,还是枚举到自身位置的最大值,如果是上界的前缀就只能枚举当自身位置的最大值,
不是就可以从0枚举到9.还有一个参数是用来表示前缀的最后一位是否为6的状态,
不为6,ret+=dp[len-1][0],
为6,ret+=dp[len][1];
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std;
#define LL long long
LL dp[][];
int digit[]; LL dfs(int len,bool state,bool fp)
{
if(!len) //len能减到0,说明枚举的这个长度为len的数不含4和62
return ;
if(!fp && dp[len][state] != -) //如果不是前缀,并且已经被计算过
return dp[len][state];
//是前缀的话,说明dp[len][state]不能用,就得重新搜索(枚举)。
LL ret = ;int fpmax = fp ? digit[len] : ;
for(int i=;i<=fpmax;i++) //分别算出以i开头的数的方案数,
//62,062,0062,因为位数是固定的,假设是m位,那么都不足m位,后面肯定有东西
{
if(i== || state && i == )
continue;
//i如果不是6的话,ret+=dp[len][0],如果是6的话,ret+下一位就不能为2的个数
ret += dfs(len-,i == ,fp && i == fpmax);
//第二个参数来保存前缀的最后一位是否为6的状态,如果为6,下一位就不能为2,否则没有限制
//第三个参数表明是否是前缀,如果是前缀,下一位就只能枚举到最大值,否则就没有限制
}
if(!fp) //如果是前缀,当前得到的ret的值,就不能代表dp[len][state]的值
dp[len][state] = ret;
return ret; //ret代表0到n不含4和62的个数
} LL f(LL n)
{
int len = ;
while(n)
{
digit[++len] = n % ;
n /= ;
}
return dfs(len,false,true);
} int main()
{
//freopen("test.txt","r",stdin);
LL a,b;
memset(dp,-,sizeof(dp));
while(cin>>a>>b)
{
if(a== && b==)
break;
cout<<f(b)-f(a-)<<endl;
} return ;
}
比较这两种方式的异同点,递推是利用具有相同前缀的数含4或62的方案数,跟去掉前缀之后的方案数相等这一特性,
而dfs是利用记录是否为前缀这一状态,搜索时,来判断每一位枚举的范围.记忆化搜索得到答案.
dfs纯属按位枚举每一位,然后从最低位回溯进行递推。
hdu2089(数位DP 递推形式)的更多相关文章
- BZOJ 3329: Xorequ(数位dp+递推)
传送门 解题思路 可以把原式移项得\(x\)^\(2x\)=\(3x\),而\(x+2x=3x\),说明\(x\)二进制下不能有两个连续的\(1\).那么第一问就是一个简单的数位\(dp\),第二问考 ...
- BZOJ3329 Xorequ[数位DP+递推矩阵快速幂]
数 位 D P 开 long long 首先第一问是转化. 于是就可以二进制下DP了. 第二问是递推,假设最后$n-1$个01位的填法设为$f[i-1]$(方案包括 ...
- hdu 2604 Queuing(dp递推)
昨晚搞的第二道矩阵快速幂,一开始我还想直接套个矩阵上去(原谅哥模板题做多了),后来看清楚题意后觉得有点像之前做的数位dp的水题,于是就用数位dp的方法去分析,推了好一会总算推出它的递推关系式了(还是菜 ...
- dp递推 数字三角形,dp初学者概念总结
数字三角形(POJ1163) 在上面的数字三角形中寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大.路径上的每一步都只能往左下或 右下走.只需要求出这个最大和即可,不必给出 ...
- Power oj2498/DP/递推
power oj 2498 /递推 2498: 新年礼物 Time Limit: 1000 MS Memory Limit: 65536 KBTotal Submit: 12 Accepted: 3 ...
- BZOJ4321queue2——DP/递推
题目描述 n 个沙茶,被编号 1~n.排完队之后,每个沙茶希望,自己的相邻的两 人只要无一个人的编号和自己的编号相差为 1(+1 或-1)就行: 现在想知道,存在多少方案满足沙茶们如此不苛刻的条件. ...
- Shell Necklace (dp递推改cdq分治 + fft)
首先读出题意,然后发现这是一道DP,我们可以获得递推式为 然后就知道,不行啊,时间复杂度为O(n2),然后又可以根据递推式看出这里面可以拆解成多项式乘法,但是即使用了fft,我们还需要做n次多项式乘法 ...
- hdu 1723 DP/递推
题意:有一队人(人数 ≥ 1),开头一个人要将消息传到末尾一个人那里,规定每次最多可以向后传n个人,问共有多少种传达方式. 这道题我刚拿到手没有想过 DP ,我觉得这样传消息其实很像 Fibonacc ...
- UVA 10559 Blocks(区间DP&&递推)
题目大意:给你玩一个一维版的消灭星星,得分是当前消去的区间的长度的平方,求最大得分. 现在分析一下题目 因为得分是长度的平方,不能直接累加,所以在计算得分时需要考虑前一个状态所消去的长度,仅用dp[l ...
随机推荐
- SpringBoot Beans定义 连接池
SpringBoot Beans定义 原有Spring框架,定义Bean方法如下 xml配置 组件扫描.@Controller.@Service... 原有Spring框架,参数注入方法如下 常用的参 ...
- ListView更新问题
ListView和Adapter对象均具备有对象更新方法 ListView对象列表的更新方法1.invalidate();--重绘组件2.invlidateView()--重绘组件并包含所有的View ...
- msp430入门编程17
msp430中C语言的寄存器操作 msp430入门学习 msp430入门编程
- DNS Prefetch 【DNS 预解析技术】
DNS 实现域名到IP的映射.通过域名访问站点,每次请求都要做DNS解析.目前每次DNS解析,通常在200ms以下.针对DNS解析耗时问题,一些浏览器通过DNS Prefetch 来提高访问的流畅性. ...
- Python()- 面向对象三大特性----多态
多态: python 生来支持多态白话:一种事物的多种形态 (动物可以继承给狗,也可以继承给猫) class Animal: pass class Dog(Animal): def attack(se ...
- 权限对于目录和文件的具体含义 linux
权限对于具体文件的含义 文件上存储具体数据的地方,包括一般文件,数据库文件,二进制可执行文件等.因此权限对于文件的意义上这样都 r: 可读权限,表示可以读取该文件的内容 w:可写权限,表示可以编辑,新 ...
- java学习——关于java课件上动手动脑问题简单的分析
问题一:关于以下的代码为什么会产生错误的问题的简单分析. 第一个动手动脑提供了一下的代码,可以发现,在Foo的这个类中只定义了一个Foo(int)类型的构造函数,在之前的学习工程中,我们并没有接触到j ...
- Win7查看本地是否安装JDK及安装路径的方法
工具/原料 win7 方法/步骤 1 开始->点击运行,输入:cmd 2 然后在命令提示符中,输入:java -version 假如看到有版本提示那么安装成功 3 假如忘记了java ...
- C语言必会面试题(3、耶稣有13个门徒,当中有一个就是出卖耶稣的叛徒,请用排除法找出这位叛徒:13人围坐一圈,从第一个開始报号:1,2,3,1,2,3...。凡是报到“3”就退出圈子,...)
3.耶稣有13个门徒.当中有一个就是出卖耶稣的叛徒,请用排除法找出这位叛徒:13人围坐一圈,从第一个開始报号:1.2,3.1,2,3.... 凡是报到"3"就退出圈子.最后留在圈子 ...
- Java注释中的@deprecated与源代码中的@Deprecated
用 @Deprecated注释的程序元素,不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择.在使用不被赞成的程序元素或在不被赞成的代码中执行重写时,编译器会发出警告. 其次,请注意标题, ...