re:从零开始的数位dp

Posted mxang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了re:从零开始的数位dp相关的知识,希望对你有一定的参考价值。

起源:唔,,前几天打cf,edu50那场被C题虐了,决定学学数位dp,此文持续更新,9.16号之前会更新完的。

ps:我也什么都不会遇到一些胡话大家不要喷我啊。。。

数位dp问题:就是求在区间l到r上满足规定条件的数的个数。

ex1:hdu3555

  题意:给你n,求从一到n中有多少个数不包含“49”。(t<=1e4,n<=2^63-1)

  首先数位dp顾名思义就是对数位进行dp嘛,所以dp数组的第一维我们用来保存数字的位数,第二位我们用来判定当前位是否为4,

所以就是  dp[20][2];  这个样子。 在这之前我们先考虑一下常规的搜索思路,一件非常显然的事情,在[1,1000]和[1001,2000]以及所有类似区间里符合要求的数都是一样的,这样我们就可以通过记忆化的方式来保存某些结果。

先给出solve函数

技术分享图片
1 ll solve(ll num){
2     int k = 0;//记录数位
3     while(num){
4         k++;
5         digit[k]=num%10;
6         num/=10;
7     }
8     return dfs(k,false,true);
9 }
View Code

 

这个很好理解嘛,保存这个数各位上的数字。然后我们就可以进行记忆化搜索了,

dp[20][2]:表示 1.有4的时候有几个含有49, 2.没有4的时候,有几个含有49。

ll dfs(int len,bool if4,bool limit){
//当前是第几位,上一位是否是4,上一位是否是上界
if(len==0)//统计完了直接返回1
return 1;
if(!limit&&dp[len][if4])//不是上界并且这种情况已经统计过
return dp[len][if4];
ll cnt=0,up_bound=(limit?digit[len]:9);//up_bound是当前位能满足的最大值,如果上一位是上界的话,当前位最大只能取到当前位的数字,如果不是,当前位可以从0取到9
for(int i=0;i<=up_bound;i++){
if(if4&&i==9)
continue;//上一位是4并且这一位是9,GG了啊
cnt+=dfs(len-1,i==4,limit&&i==up_bound);//上一位是上界的情况下我们才会考虑这一位是否是上界
}
if(!limit)//不是上界,属于通用的情况,我们进行赋值
dp[len][if4]=cnt;
return cnt;
}
最后结果差分一下就好。

ex2:hdu2089
和上道题几乎一样,条件是没有“4”并且没有“62”,
这时候我们掏出上一道题的板子了嘛肯定要,只需要在判断时加入一句话就行,在代码中加上注释了,就不做多解释了
技术分享图片
#include <bits/stdc++.h>
using namespace std;
int n,m;
int digit[10];
int dp[10][2];
int dfs(int len,bool if6, bool limit){
    if(len==0)
        return 1;
    if(!limit&&dp[len][if6])
        return dp[len][if6];
    int cnt = 0,up_bound = (limit?digit[len]:9);
    for(int i=0;i<=up_bound;i++){
        if(i==4)//如果遇到四就直接GG
            continue;
        if(if6&&i==2)
            continue;
        cnt+=dfs(len-1,i==6,limit&&i==up_bound);
    }
    if(!limit)
        dp[len][if6]=cnt;
    return cnt;
}
int solve(int num){
    int k = 0;//记录数位
    while(num){
        k++;
        digit[k]=num%10;
        num/=10;
    }
    return dfs(k,false,true);
}

int main(){
    while (scanf("%d%d",&n,&m)&&(n+m)) {
        cout << solve(m) - solve(n - 1) << endl;
    }
}
View Code

  

  ex3:



 
























以上是关于re:从零开始的数位dp的主要内容,如果未能解决你的问题,请参考以下文章

从零开始配置vim(27)——代码片段

从零开始配置vim(27)——代码片段

从零开始配置vim(27)——代码片段

从零开始的DP练习册

Re:从零开始的西柚计科院主页

HDU 2089 数位dp入门