概念:所谓数位”dp“,是指对数字的”位“进行的与计数有关的DP。一个数一个位,十位,百位,千位等,数的每一位就是数位。数位DP用来解决与数字操作有关的问题。例如数位之和的问题。特定数字问题等。这些问题的特征就是给定的区间不能超级大,不用用暴力的方法逐个检查,必须接近O(log2n) 复杂度的算法。解题的思路是用DP对”数位“进行操作,记录已经算过的区间状态,用在后续计算中,快速进行大范围的筛选。

实现方法:1.递推实现 2.用记忆法搜索实现。

一.递推的实现:

    我们来看一到例题:统计[0,n]内不含4的数字个数(直接上代码)

#include<cstdio>
#include<algorithm>
#include<set>
#include<iostream>
using namespace std;
const int maxn=2e5+5;
const int M=15;
int dp[M][M]; //dp[i][j]表示i位数字第一个数是j是符合条件的数字数量;
int bit[M]; //bit[i]存第i位数字;
void init()
{
dp[0][0]=1;
for(int i=1;i<=M;i++)
{
for(int j=0;j<10;j++)
{
for(int k=0;k<10;k++)
{
if(j!=4) dp[i][j]+=dp[i-1][k];
}
}
}
}
//计算[0,n]区间内满足条件数字的个数;
int solve(int len)
{
int ans=0;
for(int i=len;i>=1;i--) //从高位到地位处理;
{
for(int j=0;j<bit[i];j++)
if(j!=4) ans+=dp[i][j];
if(bit[i]==4) {ans--;break;} //i位开头是4的都不行;
}
return ans;
}
int ok(int x) //简单的一个求bit数组以及n的位数;
{
int len=0;
while(x)
{
bit[++len]=x%10;
x/=10;
}
return solve(len);
}
int main()
{
int n;
init(); //预计算dp[][];
cin>>n;
printf("%d\n",ok(n)+1); //不要忘记0也是符合条件;
return 0;
}

二.记忆化搜索:

 记忆化搜索的思路其实是在递归程序dfs中搜索所以可能的情况,但是遇到已经算过的记录在dp[ ]中的结果就可以直接使用,减少了重复计算。然后记忆化搜索是有模板(这让我这种dp菜鸡有一丝丝动力)

const int M=15;
int dp[M][sta]; //sta对应不同转态;
int bit[M];
int dfs(int pos,/*sta变量*/,int lead/*前导零*/,int lim/*数位上界变量*/)
{
if(pos==-1) return 1; //判断是否枚举到最低位;或者有些题目用于剪枝; if(!lim&&dp[pos][sta]!=-1) return dp[pos][sta]; int up=lim?bit[pos]:9; int ans=0; //计数;
for(int i=0;i<=up;i++)
{
if()...
else if()...
//不同题目的要求不同;
//这里是记忆化搜索最灵活的部分要具体题目分析; ans+=dfs(pos-1,/*sta状态转移*/,lead&&i==0,lim&&i==bit[pos]);
}
if(!lim) dp[pos][sta]=ans;
return ans;
}
int solve(int x)
{
int len=0;
while(x)
{
bit[len++]=x%10;
x/=10;
}
return dfs(len-1,/*从最高位开始枚举sta状态*/,/*一系列状态*/,1);
}
int main()
{
int l,r;
while(~scanf("%d%d",&n,&m))
{
memset(dp,-1,sizeof dp); //dp数组初始化,这个也可以放在while外面;
printf("%d\n",solve(r)-solve(l-1));
}
return 0;
}

看了模板我们来看几题例题:

1.Hdu 2089 题意是统计[n,m]内不含4且没有“62”的数:

代码如下:

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
#include<string>
using namespace std;
typedef unsigned long long ull;
const int maxn=4e2+5;
const int Inf=0x3f3f3f3f;
int dp[15][15];
int bit[15];
int dfs(int pos,int pre,int sta,int lim) //pre记录前一个数字;
{
if(pos<=-1) return 1;
if(!lim&&dp[pos][sta]!=-1) return dp[pos][sta];
int up=lim?bit[pos]:9;
int ans=0;
for(int i=0;i<=up;i++)
{
if(pre==6&&i==2) continue; //如果前一个数字是六现在补上的是2那么跳过循环;
if(i==4) continue;
ans+=dfs(pos-1,i,i==6,lim&&i==bit[pos]);
}
if(!lim) dp[pos][sta]=ans;
return ans;
}
int solve(int x)
{
int pos=0;
while(x)
{
bit[pos++]=x%10;
x/=10;
}
return dfs(pos-1,0,0,1);
}
int main()
{
int l,r;
memset(dp,-1,sizeof dp);
while(~scanf("%d%d",&l,&r)&&r+l)
{
printf("%d\n",solve(r)-solve(l-1));
}
return 0;
}

2.Hdu 3652 题意是求[1,n]中能被13整除且包含“13”的数。这题较上题多一个整除的判断处理需要多开一维来记录余数:

代码如下:

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
#include<string>
using namespace std;
typedef unsigned long long ull;
const int maxn=1e5+5;
int dp[15][15][3];
//dp[i][j][k]
//i:数位
//j:余数
//k:3种操作状况,0:末尾不是1 , 1:末尾是 1 ,2:含有13 int bit[15];
int dfs(int pos,int mod,int have,int lim)
{
if(pos<=0) return mod==0&&have==2; //枚举完成返回合理的数字即 能被13整除且包含“13”;
if(!lim&&dp[pos][mod][have]!=-1) return dp[pos][mod][have];
int up=lim?bit[pos]:9;
int mod_x,have_x;
int ans=0;
for(int i=0;i<=up;i++)
{
mod_x=(mod*10+i)%13; //其实是模拟除法;
have_x=have;
if(have==0&&i==1) //末尾数字是不是1现加入1,末尾为1;
have_x=1;
if(have==1&&i!=1) //末尾是1 现加入的不为1 末尾不是1;
have_x=0;
if(have==1&&i==3) //包含“13” 标记为2;
have_x=2;
ans+=dfs(pos-1,mod_x,have_x,lim&&i==bit[pos]);
}
if(!lim) dp[pos][mod][have]=ans;
return ans;
}
int solve(int x)
{
int len=0;
while(x)
{
bit[++len]=x%10;
x/=10;
}
return dfs(len,0,0,1);
}
int main()
{
int n;
memset(dp,-1,sizeof dp);
while(~scanf("%d",&n)) cout<<solve(n)<<endl;
return 0;
}

这两题是比较基础的数位dp,主要用于熟悉记忆化搜索的模板(hdu 3555类似于HDU2089 大家可以试试)

比较难的有 hdu 6148,hdu 4507大家可以挑战挑战。

个人感觉数位dp比一般的dp更容易理解,大家多花点时间效果是很明显的。

数位dp 模板加例题的更多相关文章

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

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

  2. POJ 3286 How many 0's(数位DP模板)

    题目链接:http://poj.org/problem?id=3286 题目大意: 输入n,m,求[n,m]的所有数字中,0出现的总数是多少,前导零不算. 解题思路: 模板题,设dp[pos][num ...

  3. 数位dp模板 [dp][数位dp]

    现在才想到要学数位dp,我是不是很弱 答案是肯定的 以一道自己瞎掰的题为模板 //题: //输入数字n //从0枚举到n,计算这n+1个数中含有两位数a的数的个数 //如12930含有两位数93 #i ...

  4. 51nod 1009 数字1的数量(数位dp模板)

    给定一个十进制正整数N,写下从1开始,到N的所有正数,计算出其中出现所有1的个数. 例如:n = 12,包含了5个1.1,10,12共包含3个1,11包含2个1,总共5个1.   数位dp的模板题   ...

  5. 51nod 1009 - 数字1的数量 - [数位DP][模板的应用以及解释]

    题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1009 基准时间限制:1 秒 空间限制:131072 KB 给 ...

  6. HDU - 4722 Good Numbers 【找规律 or 数位dp模板】

    If we sum up every digit of a number and the result can be exactly divided by 10, we say this number ...

  7. 【hdu6148】Valley Numer【数位dp模板题】

    题意 对于每组数据给出一个整数n(length(n)<=100),找出不大于n的数字中有多少是Valley Numer.对于Valley的定义是它每一位的数字要么是递增,要么是递减,要么是先递减 ...

  8. HDU 3555 Bomb(数位DP模板啊两种形式)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555 Problem Description The counter-terrorists found ...

  9. HDU 2089 不要62 数位DP模板题

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2089 参考博客:https://www.cnblogs.com/HDUjackyan/p/914215 ...

随机推荐

  1. 关于Matlab GUI的一些经验总结

    注:此文来自转载,侵删去年做了一些关于Matlab GUI的程序,现在又要做相关的东西,回想起来,当时很多经验没有记录下来,现在回顾起来始终觉得不爽,所以从现在开始,一定要勤写记录. 从简单的例子说起 ...

  2. Redis-第八章节-应用场景

    目录 概述 详解 1.概述 Redis支持五种数据类型:String(字符串).Hash(哈希).List(列表).Set(集合).Zset(有序集合). 2.详解 1.String(字符串) 定义: ...

  3. adjust All In One

    adjust All In One 调整 https://www.adjust.com/ Maximize the impact of your mobile marketing Adjust is ...

  4. TypeScript & Canvas 实现可视化白板

    TypeScript & Canvas 实现可视化白板 https://excalidraw.com/ https://github.com/excalidraw/excalidraw ref ...

  5. ES6 Set All In One

    ES6 Set All In One Set 集合 Map 字典/地图 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Referenc ...

  6. what's the difference amount of pdf, epub, and mobi format

    what's the difference amount of pdf, epub, and Mobi format What is the difference between pdf, epub ...

  7. css var all in one & html & root & :root

    css var all in one number :root{ --num: 0; } html{ --num: 0; } let html = document.querySelector(`ht ...

  8. 知名金融媒体采访行业大咖,多方推动BGV茁壮成长

    近来,多家知名金融媒体如纽约金融时报.伦敦金融时报等采访NGK官方代表洛索斯夫,以及美国当地行业大咖马库斯等人. 受访的NGK官方代币洛索斯夫回答道,近期官方将会推出NGK的书籍<NGK公链底层 ...

  9. django学习-23.admin管理后台的数据表数据的自定义展示

    目录结构 1.前言 2.自定义设置一张指定的数据表的列表展示内容 2.1.第一步:如果我们想让数据表[hello_person]里面的表字段值全部展示出来,需在应用[hello]里的[admin.py ...

  10. ElasticSearch 文档及操作

    公号:码农充电站pro 主页:https://codeshellme.github.io 本节介绍 ES 文档,索引及其基本操作. 1,ES 中的文档 在 ES 中,文档(Document)是可搜索数 ...