hdu 2089 不要62【数位dp】

HDU 2089

求给定区间内不含62和4的数的个数。

数位dp入门。从这里我清楚了一些数位dp的用法。比如limit是判断是否达到上界,而且需要判断(!limit).。比如若题目要求不含11的个数,举例来说:区间在[1,215],当百位开始枚举为0时,十位枚举1,个位可以取0,2~9,即dp[0][1]=9,表示枚举到个位前一位为1时满足的个数,当然此时除了1都满足。而回溯枚举到百位为2,十位为1时,由于dp[0][1]已经枚举了,可以直接返回,但此时返回时有错误的,dp[0][1]=9,而百位为2,十位为1,个位是有限制的。所以记忆化判断是必须要有(!limit),否则会造成重复且答案错误。

所以可以设计dp[pos][sta]表示枚举到第pos为状态为sta时的合法个数。sta指前一位是否为6,所以sta=0或sta=1。

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 int dp[20][2];
 5 int digit[20];
 6
 7 int dfs(int pos,int pre,int sta,bool limit)
 8 {
 9     if(pos==-1) return 1;
10     if(!limit&&dp[pos][sta]!=-1) return dp[pos][sta];
11     int up=limit?digit[pos]:9;
12     int tmp=0;
13     for(int i=0;i<=up;i++){
14         if(pre==6&&i==2) continue;
15         if(i==4) continue;
16         tmp+=dfs(pos-1,i,i==6,limit&&i==digit[pos]);
17     }
18     if(!limit) dp[pos][sta]=tmp;
19     return tmp;
20 }
21
22 int solve(int x)
23 {
24     int pos=0;
25     while(x){
26         digit[pos++]=x%10;
27         x/=10;
28     }
29     return dfs(pos-1,-1,0,true);
30 }
31
32 int main()
33 {
34     int n,m;
35     while(cin>>n>>m,!(n==0&&m==0))
36     {
37         memset(dp,-1,sizeof(dp));
38         cout<<solve(m)-solve(n-1)<<endl;
39     }
40     return 0;
41 }

既然sta已包含前一位的信息,所以我觉得dfs时不记录pre也行。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 const int N=10;
 6 int dp[N][2];
 7 int digit[N];
 8
 9 int dfs(int pos,int sta,bool limit)
10 {
11     if(pos==0) return 1;
12     if(!limit&&dp[pos][sta]!=-1) return dp[pos][sta];
13     int up=limit?digit[pos]:9;
14     int ans=0;
15     for(int i=0;i<=up;i++){
16         if(sta&&i==2) continue;
17         if(i==4) continue;
18         ans+=dfs(pos-1,i==6,limit&&i==digit[pos]);
19     }
20     if(!limit) dp[pos][sta]=ans;
21     return ans;
22 }
23
24 int solve(int x)
25 {
26     int pos=0;
27     while(x)
28     {
29         digit[++pos]=x%10;
30         x/=10;
31     }
32     return dfs(pos,0,true);
33 }
34
35 int main()
36 {
37     int n,m;
38     while(cin>>n>>m,!(n==0&&m==0))
39     {
40         memset(dp,-1,sizeof(dp));
41         cout<<solve(m)-solve(n-1)<<endl;
42     }
43     return 0;
44 }
时间: 2024-10-09 05:52:17

hdu 2089 不要62【数位dp】的相关文章

[ACM] hdu 2089 不要62(数位Dp)

不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 19043    Accepted Submission(s): 6442 Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer). 杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就

HDU 2089 不要62(数位DP,三种姿势)

HDU 2089 不要62(数位DP,三种姿势) ACM 题目地址:HDU 2089 题意: 中文题意,不解释. 分析: 100w的数据,暴力打表能过 先初始化dp数组,表示前i位的三种情况,再进行推算 直接dfs,一遍搜一变记录,可能有不饥渴的全部算和饥渴的部分算情况,记录只能记录全部算(推荐看∑大的详细题解Orz) 代码: 1. 暴力 (以前写的) /* * Author: illuz <iilluzen[at]gmail.com> * File: 2089_bf.cpp * Create

HDU 2089 不要62(数位dp)

题意:给定一个区间[n, m],求这个区间当中不含62和4的个数.例如62315,88914就是不符合条件的. 数位dp第一题,dp[i][j]表示以 j 开头的 i 位数满足条件的个数,先要预处理出来所有的情况, 下面是预处理的核心.其中k表示j后面的那一位.max_len是题目中给的n的最大位数,这里是7,第二层for是枚举第max_len - i位的值. for (int i = 1; i <= max_len; i++) { for (int j = 0; j <= 9; j++) {

HDU 2089 不要62(数位dp&amp;记忆化搜索)

题目链接:[kuangbin带你飞]专题十五 数位DP C - 不要62 题意 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer). 杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众. 不吉利的数字为所有含有4或62的号码.例如: 62315 73418 88914 都属于不吉利号码.但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列. 你的任务是,对于每次给

HDU 2089 不要62 (数位dp水题)

不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 32358    Accepted Submission(s): 11514 题目链接 Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer).杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样

HDU 2089 不要62 数位DP入门

Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer).杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众.不吉利的数字为所有含有4或62的号码.例如:62315 73418 88914都属于不吉利号码.但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列.你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多

HDU 2089 不要62 数位dp(入门

题目链接:点击打开链接 中文题. 问区间内有多少个合法数字(一个数是合法数字须满足1.不含4 ,2.每个6后面都不是2 dp[i][0]表示长度为i的数字中,前一位不为6时的合法个数, dp[i][1]表示长度为i的数字中前一位是6的合法个数. #include <cstdio> #include <algorithm> #include <cstring> #include <iostream> using namespace std; typedef l

HDU 2089 不要62 (数位DP)

Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer).杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众.不吉利的数字为所有含有4或62的号码.例如:62315 73418 88914都属于不吉利号码.但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列.你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多

hud 2089 不要62 (数位dp)

#include<stdio.h> #include<string.h> #include<math.h> #define max 10 int dp[max][3]; int number[max]; //dp[i][0] 前i位数中不符合要求的总个数 //dp[i][1] 前i位数中最高位是2的个数 //dp[i][2] 前i位数中存在含4和有连续62的个数 void init() { memset(dp,0,sizeof(dp)); dp[0][0]=1; for

HDU 3555 Bomb ,HDU 2089 深刻学习数位dp (各种方法乱用)

数位dp是与数位有关的区间统计 参考: 点击打开链接 思想是将数字拆分,dp[i][j] 长度为i的数字有多少个满足j条件的,从000~999 统计时,计当前数字为x,则其后面数字的变化的倍数是0~x-1 后面接000~999这样刚好统计不到这个数字n本身. eg: 对于一个数,若其首位已经比询问上界小,则剩余位没有任何限制.此时如果能直接处理这一情况,则问题距离解决又会迈出一大步. 例如,在十进制下,计算[10000,54321]内的数字和,我们可以将其分解为: [10000,19999],[