☆ [HDU2089] 不要62「数位DP」
类型:数位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」的更多相关文章
- HDU2089 ------不要62(数位dp)
不要62 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submi ...
- HDU2089 不要62 题解 数位DP
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2089 题目大意:求区间 \([l,r]\) 范围内不包含数字"4"且不包含连续的数 ...
- hdu2089不要62(数位dp)
#include <stdio.h> #include <string.h> ][]; ]; /* dp[i][0] 不含62,4 dp[i][1] 2开头 dp[i][2] ...
- HDU 2089 不要62(数位dp入门)
题意:统计区间 [a,b] 中不含 4 和 62 的数字有多少个. 题解:这是数位DP的入门题了,首先要理解数DP的原理,DP[i][j]:代表第i位的第j值,举个栗子:如4715 数位数是从右向 ...
- hdu2089 不要62--经典数位DP
一道十分经典的数位DP的题目. dp[i][j]表示最高位是数字i,连同最高位在内共有j位.注意边界的初始化. 接下来就是区间划分,特殊情况处理.....对了,如果不知道自己的方法是否正确,可以写一个 ...
- HDU 2089 不要62 【数位dp】
<题目链接> 不要62 Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer).杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照 ...
- HDU 2089 不要62(数位dp模板题)
http://acm.hdu.edu.cn/showproblem.php?pid=2089 题意:求区间内不包含4和连续62的数的个数. 思路: 简单的数位dp模板题.给大家推荐一个好的讲解博客.h ...
- HDU 2089 不要62【数位DP入门题】
不要62 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- 【ACM】不要62 (数位DP)
题目:http://acm.acmcoder.com/showproblem.php?pid=2089 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer).杭州交通管理局经常会扩充一些的士车牌照,新 ...
随机推荐
- ReactJs移动端兼容问题汇总
汽车H5使用ReactJs问题汇总 Q:安卓4.4webview显示空白? A:初步怀疑是css属性没有加前缀引发的兼容问题,但添加后发现也不行,通过webview调试后控制台输出Set is und ...
- 微信小程序页面跳转方法总结
微信小程序页面跳转目前有以下方法(不全面的欢迎补充): 1. 利用小程序提供的 API 跳转: // 保留当前页面,跳转到应用内的某个页面,使用wx.navigateBack可以返回到原页面.// 注 ...
- CF892/problem/C
题目传送门: [http://codeforces.com/contest/892/problem/C] 题意: 给你一个长度为n的数组,相邻两个元素的GCD(最大公约数)可以取代二者的任意一个,问你 ...
- abaqus安装破解
软件安装包 链接:http://pan.baidu.com/s/1pL4oxfX 密码:on1g 破解网页视频链接https://v.youku.com/v_show/id_XMTg4ODM5NjY5 ...
- openstack-KVM-Memory
一.Memory 1.查看memory信息 free -g cat /proc/meminfo dmesg | grep Memory 2.xml文件中的内存信息: vim /etc/libvirt/ ...
- 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为浮点数,其值在运行时由键盘输入 ...
- IdentityServer4【QuickStart】之切换到混合流并且添加API访问
切换到混合流并且添加API访问 前面的示例中我们开发了API访问和用户认证,现在我们要将两个合并到一起. OpenID Connect&OAuth 2.0组合的美妙之处是,你可以使用单一协议和 ...
- array_filter与array_map
php数组array_filter函数和array_slice函数:<?php /* array_filter()用回调函数过滤数组中的单元 array_filter(array,functio ...
- [转帖]Windows 内核说明
来源:https://zhidao.baidu.com/question/398191459.html 自己的理解. windows 的内核文件 是在 c:\windows\system32 目录下面 ...
- vue的定位
高德定位 https://blog.csdn.net/YY110621/article/details/87921605(copy) 话不多说,直接写方法步骤,需要的直接拿去放在自己项目中即可使用先看 ...