数位 dp 总结
数位 dp 总结
特征
问你一个区间 \([L,R]\) 中符合要求的数的个数
一个简单的 trick :把答案拆成前缀和 \(Ans(R)-Ans(L-1)\)
如何求 \(Ans()\) ,就要用到数位 dp
核心
其实就是记忆化搜索,不建议用循环实现,一是麻烦,二是不会
一般地,设 \(f_{x,\cdots,op}\) 为从最高位到第 \(x\) 位满足一些状态时是否时上一位是否是最高位
只要先将 \(v\) 按照题目要求拆到数组里,然后进行 dfs 算答案即可
递归边界:若 \(x=0\) ,检查当前状态是否合法并返回
有前导零的情况,需要多一个参数
int dfs(int x,...,int op) {
if(!x)return ...;
if(~f[x][...][op])
return f[x][...][op];
register int mx=op?num[x]:1,res=0;
for(int i=0;i<=mx;i++)
res+=dfs(x-1,...,op&(i==mx));
return f[x][...][op]=res;
}
例 1 windy 数
求区间内有多少 不含前导零且相邻两个数字之差至少为 2 的正整数
记录上一个数是多少即可,还可以顺便判断前导零的情况
#include<bits/stdc++.h>
using namespace std;
int L,R,len,num[20],f[20][20][2];
int dfs(int x,int ls,int op) {
if(!x)return 1;
if(~f[x][ls][op])return f[x][ls][op];
register int mx=op?num[x]:9,res=0;
for(int i=0;i<=mx;i++) {
if(abs(ls-i)<2)continue;
if(!i && ls==15)
res+=dfs(x-1,15,op&(i==mx));
else res+=dfs(x-1,i,op&(i==mx));
}
return f[x][ls][op]=res;
}
inline int Ans(int x) {
memset(f,-1,sizeof(f));
len=0;
for(;x;x/=10)num[++len]=x%10;
return dfs(len,15,1);
}
int main() {
while(scanf("%d%d",&L,&R)!=EOF)
printf("%d",Ans(R)-Ans(L-1));
}
例 2 Round Numbers S
如果一个正整数的二进制表示中,0 的数目不小于 1 的数目,那么它就被称为「圆数」。
计算区间 \([l,r]\) 中有多少个「圆数」。
分别记录 0 的个数和 1 的个数,需要判断前导零,记得用二进制
#include<bits/stdc++.h>
using namespace std;
int L,R,len,num[40],f[40][40][40][2];
int dfs(int x,int s0,int s1,int op,int fir) {
if(!x)return s0>=s1;
if(~f[x][s0][s1][op])
return f[x][s0][s1][op];
register int mx=op?num[x]:1,res=0;
for(int i=0;i<=mx;i++) {
if(fir && !i)res+=dfs(x-1,0,0,op&(i==mx),1);
else res+=dfs(x-1,s0+(i==0),s1+(i==1),op&(i==mx),0);
}
return f[x][s0][s1][op]=res;
}
inline int Ans(int x) {
memset(f,-1,sizeof(f)),len=0;
while(x)num[++len]=x&1,x>>=1;
return dfs(len,0,0,1,1);
}
int main() {
scanf("%d%d",&L,&R);
printf("%d",Ans(R)-Ans(L-1));
}
例 3 [CQOI2016]手机号码
计算区间 \([l,r]\) 中有多少个满足
- 有三个相同数相邻
- 不能同时出现 8 和 4
记录上一个数 \(l1\),上上个数 \(l2\),是否有连续三个 \(p3\),是否有 8 \(p8\),是否有 4 \(p4\)
如果只用考虑一个前导零可以直接枚举第一位
坑:如果不满足位数要返回 0
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL L,R,f[20][10][10][2][2][2][2];
int num[20],len;
LL dfs(int x,int l1,int l2,int p3,int p4,int p8,int op) {
if(p4 && p8)return 0;
if(!x)return p3;
if(~f[x][l1][l2][p3][p4][p8][op])
return f[x][l1][l2][p3][p4][p8][op];
register int mx=op?num[x]:9;
register LL res=0;
for(int i=0;i<=mx;i++)
res+=dfs(x-1,i,l1,p3|(i==l1 && i==l2),p4|(i==4),p8|(i==8),op&(i==mx));
f[x][l1][l2][p3][p4][p8][op]=res;
return res;
}
inline LL Ans(LL x) {
memset(f,-1,sizeof(f)),len=0;
while(x)num[++len]=x%10,x/=10;
if(len^11)return 0;
register LL ans=0;
for(int i=1;i<=num[len];i++)
ans+=dfs(10,i,0,0,i==4,i==8,i==num[len]);
return ans;
}
int main() {
scanf("%lld%lld",&L,&R);
printf("%lld",Ans(R)-Ans(L-1));
}
最后
dp 类还是要多练,这几个只是冰山一角
数位 dp 总结的更多相关文章
- 【BZOJ1662】[Usaco2006 Nov]Round Numbers 圆环数 数位DP
[BZOJ1662][Usaco2006 Nov]Round Numbers 圆环数 Description 正如你所知,奶牛们没有手指以至于不能玩"石头剪刀布"来任意地决定例如谁 ...
- bzoj1026数位dp
基础的数位dp 但是ce了一发,(abs难道不是cmath里的吗?改成bits/stdc++.h就过了) #include <bits/stdc++.h> using namespace ...
- uva12063数位dp
辣鸡军训毁我青春!!! 因为在军训,导致很长时间都只能看书yy题目,而不能溜到机房鏼题 于是在猫大的帮助下我发现这道习题是数位dp 然后想起之前讲dp的时候一直在补作业所以没怎么写,然后就试了试 果然 ...
- HDU2089 不要62[数位DP]
不要62 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- 数位DP GYM 100827 E Hill Number
题目链接 题意:判断小于n的数字中,数位从高到低成上升再下降的趋势的数字的个数 分析:简单的数位DP,保存前一位的数字,注意临界点的处理,都是套路. #include <bits/stdc++. ...
- 数位dp总结
由简单到稍微难点. 从网上搜了10到数位dp的题目,有几道还是很难想到的,前几道基本都是模板题,供入门用. 点开即可看题解. hdu3555 Bomb hdu3652 B-number hdu2089 ...
- 数位DP入门
HDU 2089 不要62 DESC: 问l, r范围内的没有4和相邻62的数有多少个. #include <stdio.h> #include <string.h> #inc ...
- 数位DP之奥义
恩是的没错数位DP的奥义就是一个简练的dfs模板 int dfs(int position, int condition, bool boundary) { ) return (condition ? ...
- 浅谈数位DP
在了解数位dp之前,先来看一个问题: 例1.求a~b中不包含49的数的个数. 0 < a.b < 2*10^9 注意到n的数据范围非常大,暴力求解是不可能的,考虑dp,如果直接记录下数字, ...
- 数位DP
题意:(hdu 4734) 我们定义十进制数x的权值为f(x) = a(n)*2^(n-1)+a(n-1)*2(n-2)+...a(2)*2+a(1)*1,a(i)表示十进制数x中第i位的数字. 题目 ...
随机推荐
- vue解决音频可视化播放,使用wavesurfer.js
vue解决音频可视化播放,使用wavesurfer.js 上效果: 1.安装wavesurfer npm install wavesurfer.js 2.在页面导入 import WaveSur ...
- 玩转NET Expression
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; ...
- python---导入模块和包
导入模块和包 导入模块 import的过程中发生了哪些事情? 寻找模块 如果找到,开辟一块空间,执行这个模块 把这个模块中用到的名字都收录到开辟的空间中 创建一个变量来引用这个模块的空间 注意: 模块 ...
- spring-注入list集合对象(值是对象)
1.创建stu类 public class Stu { // //1.数组类型 // private String[] courses; // // //2.list集合属性 // private L ...
- SpringMVC快速使用——基于注解
SpringMVC快速使用--基于注解 1.引入依赖 <!-- 定义Spring版本 --> <properties> <spring.verson>5.3.8&l ...
- Qt 实现文字输入框,带字数限制
Qt 实现文字输入框,带字数限制 核心构思 核心的点在于,限制输入的字数:主要的方法为创建一个组合窗口 textChanged 这个信号,会在你输入字符之后发射,可以连接这个信号,在发射了信号之后,去 ...
- npm 报错This is probably not a problem with npm. There is likely additional logging output above.
报错This is probably not a problem with npm. There is likely additional logging output above. 安装了一个插件后 ...
- “九韶杯”河科院程序设计协会第一届程序设计竞赛 D数列重组 next_permutation
"九韶杯"河科院程序设计协会第一届程序设计竞赛 D数列重组 next_permutation 题目 原题链接: https://ac.nowcoder.com/acm/conte ...
- 记一次docker安装成功,启动失败的原因
问题 按照错误提示,先查看docker的状态: systemctl status docker 可以看到,非常明显的一行大红字:Failed to start Docker Application C ...
- CAS如何解决ABA问题
点赞再看,养成习惯,微信搜索「小大白日志」关注这个搬砖人. 文章不定期同步公众号,还有各种一线大厂面试原题.我的学习系列笔记. CAS如何解决ABA问题 什么是ABA:在CAS过程中,线程1.线程2分 ...