---恢复内容开始---

因为最近做比赛经常会出现数位DP,便尝试着去学学看数位DP。

先给出两篇论文的链接:

数位计数问题解法研究

浅谈数位类统计问题

然后也是寻找了很多大牛的博客,学习了很多(但是没学会囧。),现在先总结一下已经学到的东西

“在信息学竞赛中,有这样一类问题:求给定区间中,满足给定条件的某个D 进制数或
此类数的数量。所求的限定条件往往与数位有关,例如数位之和、指定数码个数、数的大小
顺序分组等等。题目给定的区间往往很大,无法采用朴素的方法求解。此时,我们就需要利
用数位的性质,设计log(n)级别复杂度的算法。解决这类问题最基本的思想就是“逐位确定”
的方法。下面就让我们通过几道例题来具体了解一下这类问题及其思考方法。”——刘聪

事实上,为什么会想到用数位DP来做,就是因为限定条件往往和数位有关,而仔细地朴素的暴力方法中,所做的重复的工作太多。这样的条件会使得DP(记忆化搜索)有用武之地。

目前我所接触到的大多数的题,都是可以通过记录某些值(比如数位等)来减少重复的运算。当然,因为此类题的特殊性,可以编写check函数确定代码的正确性。

再偷用某个大牛的一句话:其实数位DP(或者说所有记忆化搜索)都是可以看做通过搜索来填满状态的值。

首先先想想数位DP的运行模式

如果我们要统计[0,54321]中满足某个条件的个数,需要将其拆分为

[00000,09999][10000,19999],[20000,29999],[30000,39999],[40000,49999],

[50000,50999],[51000,51999],[52000,52999],[53000,53999],

[54000,54099],[54100,54199],[54200,54299],

[54300,54309],[54310,54319],

[54320,54321]

为什么要这么分呢?随便举个例子,如果我们统计过了[0000,9999]中的满足条件(或者其他各种不满足条件的状态)的个数,那么分别在加上前缀,就可以判断出有多少个满足条件的个数。目的是为了将大的区间划分为小的区间进行求解。

因此,总结一句话,数位DP减少的运算量为:前面几位固定,后面几位可以任意取的个数统计。

比如分析一道简单题:HDU 3652,通过我这个渣渣的错误历程来分析一些细节上的问题

先贴错误代码

 1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 using namespace std;
5 int dp[20][20][20];
6 int num[20];
7 int dfs(int pos,int mod,int pre,int stat,int limit){
8 if(pos==0) return mod==0&&stat;
9 if(!limit&&dp[pos][mod][pre]!=-1) return dp[pos][mod][pre];
10 int ans=0;
11 int end=limit?num[pos]:9;
12 for(int i=0;i<=end;i++){
13 int nmod=(mod*10+i)%13;
14 int nstat=(pre==1&&i==3)||stat;
15 ans+=dfs(pos-1,nmod,i,nstat,limit&&i==end);
16 }
17 if(!limit) dp[pos][mod][pre]=ans;
18 return ans;
19 }
20 int cal(int x){
21 int cnt=0;
22 memset(num,0,sizeof(num));
23 while(x){
24 num[++cnt]=x%10;
25 x/=10;
26 }
27 return dfs(cnt,0,0,0,1);
28 }
29 int main()
30 {
31 int i,j;
32 int n;
33 memset(dp,-1,sizeof(dp));
34 while(scanf("%d",&n)!=EOF){
35 int ans=cal(n);
36 printf("%d\n",ans);
37 }
38 return 0;
39 }

我选取的记录参数有三个:pos当前处理位,mod前缀和余数,还有前一位的数字pre

但是运算结果却始终会小于等于正确的答案,为什么呢?

想了想,发现其实是因为参数含义的问题。

分析一下,如果我将pre作为一个关键参数记录下来,其实我并不能区分我记录的是后面几位能不能随机取的个数。

即当下一次搜索到pos,mod,pre的时候,不能确定前面是否有13,或者以前搜索的DP[pos][mod][pre]中的数的个数是否有13。

因此应该把记录的参数改为pos,mod,stat(表示为记录状态,0为不含13,1为只含前一位为1,2为前缀含有13)。

因此得到下面的AC代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[20][20][3];
int num[20];
int dfs(int pos,int mod,int stat,int limit){
if(pos==0) return mod==0&&stat==2;
if(!limit&&dp[pos][mod][stat]!=-1) return dp[pos][mod][stat];
int ans=0;
int end=limit?num[pos]:9;
for(int i=0;i<=end;i++){
int nmod=(mod*10+i)%13;
int nstat;
if(stat==1&&i==3||stat==2) nstat=2;
else if(i==1) nstat=1;
else nstat=0;
ans+=dfs(pos-1,nmod,nstat,limit&&i==end);
}
if(!limit) dp[pos][mod][stat]=ans;
return ans;
}
int cal(int x){
int cnt=0;
memset(num,0,sizeof(num));
while(x){
num[++cnt]=x%10;
x/=10;
}
return dfs(cnt,0,0,1);
}
int main()
{
int i,j;
int n;
memset(dp,-1,sizeof(dp));
while(scanf("%d",&n)!=EOF){
int ans=cal(n);
printf("%d\n",ans);
}
return 0;
}

好了讲完了

关于数位DP的学习的更多相关文章

  1. 数位DP::SoSDP

    数位DP:: SoSDP 学习博客(待补) 下面做一些例题: SPECIAL PAIRS 题意 给n个数字,求这些数字有多少对的\(AND\) 结果是0.数字不大于1e6.顺序反相反视为不同的对. 思 ...

  2. HDU3555【数位DP】

    入门...还在学习中,先贴一发大牛博客 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555 题目大意: 给一个数字n,范围在1~2^63-1,求1~ ...

  3. 掌握数位dp

    最近遇到了数位dp题目,于是就屁颠屁颠的跑过来学习数位dp了~ "在信息学竞赛中,有这样一类问题:求给定区间中,满足给定条件的某个D 进制数或此类数的数量.所求的限定条件往往与数位有关,例如 ...

  4. 数位DP学习笔记

    数位DP学习笔记 什么是数位DP? 数位DP比较经典的题目是在数字Li和Ri之间求有多少个满足X性质的数,显然对于所有的题目都可以这样得到一些暴力的分数 我们称之为朴素算法: for(int i=l_ ...

  5. MMM 数位dp学习记

    数位dp学习记 by scmmm 开始日期 2019/7/17 前言 状压dp感觉很好理解(本质接近于爆搜但是又有广搜的感觉),综合了dp的高效性(至少比dfs,bfs优),又能解决普通dp难搞定的问 ...

  6. [学习笔记] 数位DP的dfs写法

    跟着洛谷日报走,算法习题全都有! 嗯,没错,这次我也是看了洛谷日报的第84期才学会这种算法的,也感谢Mathison大佬,素不相识,却写了一长篇文章来帮助我学习这个算法. 算法思路: 感觉dfs版的数 ...

  7. 【学习笔记&训练记录】数位DP

    数位DP,即对数位进行拆分,利用数位来转移的一种DP,一般采用记忆化搜索,或者是先预处理再进行转移 一个比较大略的思想就是可以对于给定的大数,进行按数位进行固定来转移记录答案 区间类型的,可以考虑前缀 ...

  8. ACM学习历程—HDU5587 Array(数学 && 二分 && 记忆化 || 数位DP)(BestCoder Round #64 (div.2) 1003)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5587 题目大意就是初始有一个1,然后每次操作都是先在序列后面添加一个0,然后把原序列添加到0后面,然后 ...

  9. 数位DP 学习笔记

    前言:鸣谢https://www.luogu.com.cn/blog/virus2017/shuweidp.感谢大佬orz ----------------------------- [引入] 首先要 ...

随机推荐

  1. web元素定位和appium-app元素定位

    一.web页面元素定位工具介绍 1.打开google浏览器,按F12进入开发者模式,如下图: 2.用鼠标点击下图红色框中的箭头--然后鼠标移动到web页面的元素上(此处为百度框),会自动定位到对应的h ...

  2. Spring Boot GraphQL 实战 03_分页、全局异常处理和异步加载

    hello,大家好,我是小黑,又和大家见面啦~ 今天我们来继续学习 Spring Boot GraphQL 实战,我们使用的框架是 https://github.com/graphql-java-ki ...

  3. Qt开发的应用记录读取用户习惯设置的方法

    Qt开发的应用记录读取用户习惯设置的方法 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/w ...

  4. d3 zoom 抖动问题 事件

    最近在使用d3 zoom得时候   遇到一个小坑 直接对元素添加 zoom事件 会有很大得抖动,查文档 看代码之后发现是 由于元素在不断变化, 所以计算基础值也不不断变化,所以会导致计算出来得值 忽大 ...

  5. LeetCode938. 二叉搜索树的范围和

    题目 1 class Solution { 2 public: 3 int sum = 0; 4 int rangeSumBST(TreeNode* root, int low, int high) ...

  6. Eclipse中的可视化图形界面设计插件windowbuilder

    对于eclipse平台上的可视化开发工具插件,有windowbuilder.visual editor等,今天就对windowbuilder说明: WindowBuilder功能特性等介绍,参考如下网 ...

  7. python3.8.1安装cx_Freeze

    按照官网的提示命令python -m pip install cx_Freeze --upgrade安装,不成功,报了一个错误,说cx_Freeze找不到需要的版本,还有一些警告说PIP需要升级,没理 ...

  8. spring mvc + mybaties + mysql 完美整合cxf 实现webservice接口 (服务端、客户端)

    spring-3.1.2.cxf-3.1.3.mybaties.mysql 整合实现webservice需要的完整jar文件 地址:http://download.csdn.net/detail/xu ...

  9. 深度学习论文翻译解析(十七):MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications

    论文标题:MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications 论文作者:Andrew ...

  10. 转 Fiddler5 发送HTTP请求

    Fiddler5 发送HTTP请求  文章转自:https://www.cnblogs.com/zhengna/p/10879573.html 1.Fiddler Composer发送HTTP请求 C ...