数位 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位的数字. 题目 ...
随机推荐
- C语言-操作符与表达式
C语言入门之操作符与表达式 前言 本篇文章主要包括各种操作符的介绍与表达式求值,欢迎各位小伙伴与我一起学习. 一.操作符 分类 算术操作符 移位操作符 位操作符 赋值操作符 单目运算符 关系操作符 逻 ...
- SpringBoot利用自定义注解实现通用的JWT校验方案
利用注解开发一个通用的JWT前置校验功能 设计的预期: 系统中并不是所有的应用都需要JWT前置校验,这就需要额外设计一个注解Annotation来标识这个方法需要JWT前置校验.例如: @GetMap ...
- Struct2中三种获取表单数据的方式
1.使用ActionContext类 //1获取ActionContext对象 ActionContext context = ActionContext.getContext(); //2.调用方法 ...
- 设计模式学习笔记(十六)迭代器模式及其在Java 容器中的应用
迭代器(Iterator)模式,也叫做游标(Cursor)模式.我们知道,在Java 容器中,为了提高容器遍历的方便性,把遍历逻辑从不同类型的集合类中抽取出来,避免向外部暴露集合容器的内部结构. 一. ...
- sqlplus文件查看自带oracle命令的执行过程
问题描述:看到一篇文章 在$ORACLE_HOME/bin/sqlplus中可以查看到数据库命令的查询语句.可以直接编辑sqlplus文件,查到到我们平时标准系统命令的原脚本,但是自己进行编辑查看却是 ...
- 关于Electron框架应用的安全测试
Electron框架应用的安全测试 0.Electron相关简介 electron.js是一个运行时框架,它在设计之初就结合了当今最好的Web技术,核心是使用HTML.CSS.JavaScript构建 ...
- Java之IO流技术详解
何为IO? 首先,我们看看百度给出的解释. I/O输入/输出(Input/Output),分为IO设备和IO接口两个部分. i是写入,Input的首字母.o是输出,Output的首字母. IO 也称为 ...
- javascript生成一棵树
问题描述 输入一串父子节点对的数组,利用其构造一颗树 输入 const arr = [ {id:1,parentid:null}, {id:2,parentid:1}, {id:3,parentid: ...
- MySQL常用数据类型及细节
目录 1 整数类型 1.1 可选属性 1.1.1 M 1.1.2 UNSIGNED 1.1.3 ZEROFILL 2 浮点类型 2.1 精度误差 3 定点数类型 3.1 数据精度说明 3.2 类型介绍 ...
- 斯坦福NLP课程 | 第1讲 - NLP介绍与词向量初步
作者:韩信子@ShowMeAI,路遥@ShowMeAI,奇异果@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/36 本文地址:http://www. ...