文章参考:数位dp之总结

首先,什么是数位dp?它是干什么的?

数位dp是一种计数用的dp,一般就是要统计一个区间[le,ri]内满足一些条件数的个数。

举个栗子:
加入我们要枚举所有上界不超过231的数,那么我们一般的做法就是:

 for(int i=le;i<=ri;i++)
if(right(i)) ans++;

这里的le和ri分别是0和231。
方法可以是可以,但是有时候枚举量会太大,这里采用新的枚举方法:

从高位起,每次枚举每一位的数,要求每次枚举都不能超过231,比如第一位你的上界是2,那么你就只能枚举0或1或2。当你第一位枚举1的时候,你第二位就可以随便枚举0~9;但当你第一位枚举的是2,接下来那一位便只能枚举0~3。以此类推,总之就是枚举的数不能超过规定的这个上界。与此同时要注意能否出现前导0,这个看题目,代码中的lead代表了前导0。


模板代码:

 typedef long long ll;
int a[];
ll dp[][state];//不同题目状态不同
//有人可能想到把dp状态改一下dp[pos][state][limit]就是分别记录不同limit下的个数
ll dfs(int pos,/*state变量*/,bool lead/*前导零*/,bool limit/*数位上界变量*/)//不是每个题都要判断前导零
{
//递归边界,既然是按位枚举,最低位是0,那么pos==-1说明这个数我枚举完了
if(pos==-) return ;/*这里一般返回1,表示你枚举的这个数是合法的,那么这里就需要你在枚举时必须每一位都要满足题目条件,也就是说当前枚举到pos位,一定要保证前面已经枚举的数位是合法的。不过具体题目不同或者写法不同的话不一定要返回1 */
//第二个就是记忆化(在此前可能不同题目还能有一些剪枝)
if(!limit && !lead && dp[pos][state]!=-) return dp[pos][state];
/*常规写法都是在没有限制的条件记忆化,这里与下面记录状态是对应,具体为什么是有条件的记忆化后面会讲*/
int up=limit?a[pos]:;//根据limit判断枚举的上界up;这个的例子前面用213讲过了
ll ans=;
//开始计数
for(int i=;i<=up;i++)//枚举,然后把不同情况的个数加到ans就可以了
{
if() ...
else if()...
ans+=dfs(pos-,/*状态转移*/,lead && i==,limit && i==a[pos]) //最后两个变量传参都是这样写的
/*这里还算比较灵活,不过做几个题就觉得这里也是套路了
大概就是说,我当前数位枚举的数是i,然后根据题目的约束条件分类讨论
去计算不同情况下的个数,还有要根据state变量来保证i的合法性,比如题目
要求数位上不能有62连续出现,那么就是state就是要保存前一位pre,然后分类,
前一位如果是6那么这意味就不能是2,这里一定要保存枚举的这个数是合法*/
}
//计算完,记录状态
if(!limit && !lead) dp[pos][state]=ans;
/*这里对应上面的记忆化,在一定条件下时记录,保证一致性,当然如果约束条件不需要考虑lead,这里就是lead就完全不用考虑了*/
return ans;
}
ll solve(ll x)
{
int pos=;
while(x)//把数位都分解出来
{
a[pos++]=x%;//个人老是喜欢编号为[0,pos),看不惯的就按自己习惯来,反正注意数位边界就行
x/=;
}
return dfs(pos-/*从最高位开始枚举*/,/*一系列状态 */,true,true);//刚开始最高位都是有限制并且有前导零的,显然比最高位还要高的一位视为0嘛
}
int main()
{
ll le,ri;
while(~scanf("%lld%lld",&le,&ri))
{
//初始化dp数组为-1,这里还有更加优美的优化,后面讲
printf("%lld\n",solve(ri)-solve(le-));
}
}

例题:bzoj1026 Windy数
题意:
windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,在A和B之间,包括A和B,总共有多少个windy数?
输入为两个整数,输出windy数的个数。

代码如下:

 #include<cstdio>
#include<algorithm>
#include<string.h>
#include<cmath>
using namespace std;
typedef long long ll;
ll l, r;
ll dp[][][];
int dig[]; ll dfs(int pos, int pre, bool limit, bool lead) {
if (pos < )return ;
if (!limit && dp[pos][pre][lead] != -)
return dp[pos][pre][lead];
ll ans = ;
int up = limit ? dig[pos]: ;
for (int i = ; i <= up; i++) {
if (lead||abs(i - pre) >= ) {
ans += dfs(pos - , i, limit && (i == up), lead && (i == ));
}
}
if (!limit)dp[pos][pre][lead] = ans;
return ans;
} ll cal(ll n) {
int len = ;
memset(dp, -, sizeof(dp));
while (n) {
dig[len++] = n % ;
n /= ;
}
return dfs(len - , , true,);
} int main() {
scanf("%lld%lld", &l, &r);
printf("%lld", cal(r) - cal(l - ));
return ;
}

数位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用来解决与数字操作有关的问题.例 ...

  4. 数位dp整理 && 例题HDU - 2089 不要62 && 例题 HDU - 3555 Bomb

    数位dp: 数位dp是一种计数用的dp,一般就是要统计一个区间[li,ri]内满足一些条件数的个数.所谓数位dp,字面意思就是在数位上进行dp.数位的含义:一个数有个位.十位.百位.千位......数 ...

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

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

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

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

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

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

  8. 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 ...

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

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

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

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

随机推荐

  1. iis添加asp.net网站,访问提示:由于扩展配置问题而无法提供您请求的页面。如果该页面是脚本,请添加处理程序。如果应下载文件,请添加 MIME 映射

    今天在iis服务器配置asp.net网站,遇到一个问题,记录一下: 问题:由于扩展配置问题而无法提供您请求的页面.如果该页面是脚本,请添加处理程序.如果应下载文件,请添加 MIME 映射. Windo ...

  2. 【iOS】Spring Animations (弹性动画)

    This interface shows how a spring animation can be created by specifying a “damping” (bounciness) an ...

  3. system.run

    客户端开启了remotecommand后可以在server调用该命令在agent上执行一些命令 命令中有逗号 zabbix_get -s xxx.xxx.xxx.xxx -k "system ...

  4. Play! 1.x 访问远程web

    本文参考 Play Framework 控制层发起HTTP请求 (Send Http Request In Controller) 参考连接地址:http://blog.csdn.net/fhzait ...

  5. C++中字符常量与字符常量不能直接相加

    定义string变量,并进行初始化,如下: string s1 = "Hello"; string s2 = s1 + "World"; string s3 = ...

  6. 0.96寸OLED显示屏驱动手册(SSD1306)

    MCU IIC接口 IIC通信接口由从地址位SA0,IIC总线数据信号SDA(输出SDAout/D2和输入SDAin /D1)和IIC总线时钟信号SCL(D0).不管是数据线还是时钟线都需要连接上拉电 ...

  7. 爬虫数据存储——安装docker和ElasticSearch(基于Centos7)

    爬虫数据存储--安装docker和ElasticSearch(基于Centos7) 先决条件 操作系统要求 要安装Docker Engine-Community,您需要一个CentOS 7的维护版本. ...

  8. pom.xml配置文件详解(Maven)

    注:博主 Chloneda:个人博客 | 博客园 | Github | Gitee | 知乎 注:本文转载自:https://blog.csdn.net/u012152619/article/deta ...

  9. css3基础-文本与字体+转换+过渡+动画+案例

    Css3文本与字体   文本阴影 h1 { text-shadow: 5px 5px 5px red; } word-break换行: h1:nth-child(1) { word-break: no ...

  10. 剑指offer-面试题41-数据流中的中位数-堆

    /* 题目: 链接:https://www.nowcoder.com/questionTerminal/9be0172896bd43948f8a32fb954e1be1 来源:牛客网 如何得到一个数据 ...