【算法笔记】数位dp

·前言

当我们遇到某些题目的时候(比如像让你统计l——r这一个区间内的数字和以及满足条件的数有几个这一类的题目),常常会因为区间太大而无法计算。这时候,我们就需要用上我们伟大的数位dp啦!

数位dp的实质就是换一种暴力枚举的方式,使得新的枚举方式满足dp的性质,然后记忆化就可以了。(nm这本质上不还是记忆化搜索)

(PS:虽然说数位dp是可以用正常的递推算法来写的,但是递推不仅难想还难调的一批,没准就一不小心人就没了,还是用记忆化搜索板子攻克这一切吧)

(PPS:记忆化搜索背个板子就好,但是特别难查错qwq)

·基本思维

由于递推版的数位dp本质上就是个找规律枚举状态的过程,其实和记忆化搜索差不了多少(而且我不会写QAQ)。所以该篇博就讲记忆化搜索的方法就over了……

考虑一下枚举每一位(pos)的数字(记得确定一下上界(limit)qwq),以及在中途判断是否存在有前导零(lead),接下来就可以愉快地记忆化搜索啦~

state状态需要根据题目的不同而确定哦qwq

给个板子趴(

#include<bits/stdc++.h>
using namespace std;
int a[20];
long long dp[20][state];
long long dfs(int pos,int state,bool lead,bool limit){
    if(!pos)return 1;
    if(!limit&&!lead&&dp[pos][state]!=-1)return dp[pos][state];
    int up=limit?a[pos]:9;
    long long ans=0;
    for(int i=0;i<=up;i++){
        if() ...
        else if()...
        ans+=dfs(pos-1, ,lead&&i==0,limit&&i==a[pos])
    }
    if(!limit&&!lead)dp[pos][state]=ans;
    return ans;
}
long long solve(long long x){
    int pos=0;
    while(x){
        a[++pos]=x%10;
        x/=10;
    }
    return dfs(pos,1,1);
}
int main(){
    long long l,r;
    while(~scanf("%lld%lld",&l,&r))
        printf("%lld\n",solve(r)-solve(l-1));
}
View Code

·题目汇总

HDU3652 B-Number
01 Luogu4317/BZOJ3209 
02 BZOJ 1833 ZJOI2010 Count
03 HDU4734 f(x)
04 Codeforces 55D Beautiful Number
05 2012 Multi-University Training Contest 6 XHXJ’s LIS
06 HDU4507 
*依旧莫得链接,以后把题解整出来再说吧qwq
posted @ 2020-08-11 16:14  linsky  阅读(131)  评论(0编辑  收藏  举报