类型:数位DP

传送门:>Here<

题意:问区间$[n,m]$的数字中,不含4以及62的数字总数

解题思路

数位DP入门题

先考虑一般的暴力做法,整个区间扫一遍,判断每个数是否合法并累计答案。而数位DP则认为可以换一种方法来枚举,找到对于一个数的上限,然后在这个限度内枚举每一个数位来统计答案

为了方便数位DP,题意可以转化求区间$[0, k]$的符合要求的数字总数,因此答案就是$ans(M)-ans(N-1)$

首先我们可以预处理出dp数组:$dp[i][j]$表示以$j$开头的$i$位数的符合要求的数字总数;例如,$dp[2][3]$表示以3开头的2位数中符合要求的,也就是区间$[30, 39]$中符合要求的。$$dp[i][j] = \sum\limits_{0 \leq k \leq 9 \\ \ k \neq 4}dp[i-1][k]$$这个方程很好理解,相当于枚举一个数位塞到前面,同时需要保证不能把6塞当2前面,并且特判一下4就好了

至于统计答案,我们从上限的最高位开始往下扫描。这里有个很巧妙的思想——每次处理不超过当前这一位的部分。形象地说,对于数字$21358$,最高位扫描$0~1$,也就是把答案累积上$dp[5][0~1]$。这一步相当于处理了区间$[0, 19999]$中的所有;此时默认最高位是2,扫描到下一位,累积$dp[4][0~0]$,也就相当于处理了区间$[20000,20999]$;依次类推,然后将会处理$[21000,21299]$,$[21300,21349]$,$[21350,21357]$。因此我们可以在$O(lg N * 10)$的复杂度内处理区间$[0, N-1]$。(注意不包括N)$$ans = \sum\limits_{i=num}^{1}\sum\limits_{j=0}^{digit[i]-1}dp[i][j]$$

然后在来看判断62和4的问题:每当我们进入到下一位,我们就将默认上一位确定。此时若确定的那一位为4,那么之后的都不用考虑了(一定不合法)。同理,如果当前确定的为2且上一位确定的为6,那么也可以跳出。事实上,这个跳出不是优化,而是必须那么做——如果不跳出,就会错误地累积很多答案。同时,不仅进入下一位的时候要判断,扫描的时候也要判断。道理一样

拓展:如果题目要求的不是【不要62】而是【要62】呢?就好像[HDU3555] Bomb所要求的一样,只需要求出所有的【不要62】数字,用N减一下就好了

Code

特别需要注意的是$digit[num+1]==0$这一步的处理,如果不加这一步,那么如果在处理前一个数字时残留下了$digit[num+1]==6$,那么你的程序将不能在最高位填充2了!

另外还有dp数组的初始化问题:一种是$dp[0][0]=1$,或者对于所有$i \neq 4$,$dp[1][i]=1$。其实这两者是等效的,因为在统计$dp[1][i]$时,只会累积到$dp[0][0]$为1

/*By DennyQi 2018.8.13*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define r read()
#define Max(a,b) (((a)>(b)) ? (a) : (b))
#define Min(a,b) (((a)<(b)) ? (a) : (b))
using namespace std;
typedef long long ll;
const int MAXN = ;
const int MAXM = ;
const int INF = ;
inline int read(){
int x = ; int w = ; register int c = getchar();
while(c ^ '-' && (c < '' || c > '')) c = getchar();
if(c == '-') w = -, c = getchar();
while(c >= '' && c <= '') x = (x << ) + (x << ) + c - '', c = getchar(); return x * w;
}
int N,M,num,X,Y;
int dp[][],digit[];
inline void Init(){
dp[][] = ;
for(int i = ; i <= ; ++i){
for(int j = ; j <= ; ++j){
if(j == ) continue;
for(int k = ; k <= ; ++k){
if(k == && j == ) continue;
dp[i][j] += dp[i-][k];
}
}
}
}
inline int cul(int x){
num = ;
int y = x, res = ;
while(y > ){
digit[++num] = y % ;
y /= ;
}
digit[num+] = -;
for(int i = num; i >= ; --i){
for(int j = ; j < digit[i]; ++j){
if(digit[i+] == && j == ) continue;
res += dp[i][j];
}
if(digit[i] == || (digit[i+]==&&digit[i]==)) break;
}
return res;
}
int main(){
Init();
for(;;){
N = r, M = r;
if(!N && !M) break;
printf("%d\n",cul(M+)-cul(N));
}
return ;
}

☆ [HDU2089] 不要62「数位DP」的更多相关文章

  1. HDU2089 ------不要62(数位dp)

    不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submi ...

  2. HDU2089 不要62 题解 数位DP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2089 题目大意:求区间 \([l,r]\) 范围内不包含数字"4"且不包含连续的数 ...

  3. hdu2089不要62(数位dp)

    #include <stdio.h> #include <string.h> ][]; ]; /* dp[i][0] 不含62,4 dp[i][1] 2开头 dp[i][2] ...

  4. HDU 2089 不要62(数位dp入门)

    题意:统计区间 [a,b] 中不含 4 和 62 的数字有多少个. 题解:这是数位DP的入门题了,首先要理解数DP的原理,DP[i][j]:代表第i位的第j值,举个栗子:如4715   数位数是从右向 ...

  5. hdu2089 不要62--经典数位DP

    一道十分经典的数位DP的题目. dp[i][j]表示最高位是数字i,连同最高位在内共有j位.注意边界的初始化. 接下来就是区间划分,特殊情况处理.....对了,如果不知道自己的方法是否正确,可以写一个 ...

  6. HDU 2089 不要62 【数位dp】

    <题目链接> 不要62 Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer).杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照 ...

  7. HDU 2089 不要62(数位dp模板题)

    http://acm.hdu.edu.cn/showproblem.php?pid=2089 题意:求区间内不包含4和连续62的数的个数. 思路: 简单的数位dp模板题.给大家推荐一个好的讲解博客.h ...

  8. HDU 2089 不要62【数位DP入门题】

    不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  9. 【ACM】不要62 (数位DP)

    题目:http://acm.acmcoder.com/showproblem.php?pid=2089 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer).杭州交通管理局经常会扩充一些的士车牌照,新 ...

随机推荐

  1. ReactJs移动端兼容问题汇总

    汽车H5使用ReactJs问题汇总 Q:安卓4.4webview显示空白? A:初步怀疑是css属性没有加前缀引发的兼容问题,但添加后发现也不行,通过webview调试后控制台输出Set is und ...

  2. 微信小程序页面跳转方法总结

    微信小程序页面跳转目前有以下方法(不全面的欢迎补充): 1. 利用小程序提供的 API 跳转: // 保留当前页面,跳转到应用内的某个页面,使用wx.navigateBack可以返回到原页面.// 注 ...

  3. CF892/problem/C

    题目传送门: [http://codeforces.com/contest/892/problem/C] 题意: 给你一个长度为n的数组,相邻两个元素的GCD(最大公约数)可以取代二者的任意一个,问你 ...

  4. abaqus安装破解

    软件安装包 链接:http://pan.baidu.com/s/1pL4oxfX 密码:on1g 破解网页视频链接https://v.youku.com/v_show/id_XMTg4ODM5NjY5 ...

  5. openstack-KVM-Memory

    一.Memory 1.查看memory信息 free -g cat /proc/meminfo dmesg | grep Memory 2.xml文件中的内存信息: vim /etc/libvirt/ ...

  6. ocrosoft 1015 习题1.22 求一元二次方程a*x^2 + b*x + c = 0的根

    http://acm.ocrosoft.com/problem.php?id=1015 题目描述 求一元二次方程a*x2 + b*x + c = 0的根.系数a.b.c为浮点数,其值在运行时由键盘输入 ...

  7. IdentityServer4【QuickStart】之切换到混合流并且添加API访问

    切换到混合流并且添加API访问 前面的示例中我们开发了API访问和用户认证,现在我们要将两个合并到一起. OpenID Connect&OAuth 2.0组合的美妙之处是,你可以使用单一协议和 ...

  8. array_filter与array_map

    php数组array_filter函数和array_slice函数:<?php /* array_filter()用回调函数过滤数组中的单元 array_filter(array,functio ...

  9. [转帖]Windows 内核说明

    来源:https://zhidao.baidu.com/question/398191459.html 自己的理解. windows 的内核文件 是在 c:\windows\system32 目录下面 ...

  10. vue的定位

    高德定位 https://blog.csdn.net/YY110621/article/details/87921605(copy) 话不多说,直接写方法步骤,需要的直接拿去放在自己项目中即可使用先看 ...