概念:所谓数位”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. sdut2878 环形依赖的DP(高斯消元,剪枝后的模板

    这题的状态是循环依赖的有环.. 之前一道概率DP,类似有环..但是它是可以消掉的 比如dp[i]=0.3*dp[i+1]+0.2*dp[i+2]+0.5*dp[i]; 完全可以变成,0.5*dp[i] ...

  2. Linux command find All In One

    Linux command find All In One $ find -h # find: illegal option -- h # usage: # find [-H | -L | -P] [ ...

  3. flex & align-content & justify-items

    flex & align-content & justify-items align-content 多行 align-items 的对其方式 https://developer.mo ...

  4. jest & code testing

    jest jest & code testing https://jestjs.io/zh-Hans/ 24.9 https://jestjs.io/docs/zh-Hans/getting- ...

  5. .pyc & Python

    .pyc & Python Python bytecode / 字节码 Python compiles the .py files and saves it as .pyc files , s ...

  6. HTML Custom Elements (v1)

    HTML Custom Elements (v1) https://developers.google.com/web/fundamentals/web-components/customelemen ...

  7. react-parent-child-lifecycle-order

    react-parent-child-lifecycle-order react parent child lifecycle order live demo https://33qrr.csb.ap ...

  8. multi selects & mutually exclusive

    multi selects & mutually exclusive 互斥 selects import React, { useState, // useEffect, // useRef, ...

  9. input support upload excel only

    input support upload excel only demo https://codepen.io/xgqfrms/pen/vYONpLB <!-- <input placeh ...

  10. 发布npm包时,发布源码,而不是dist后的打包文件

    基于webpack-scaffold 此脚手架配置 删除.gitignore文件中对dist文件夹的无视配置 修改package.json文件 { "private": true, ...