码迷,mamicode.com
首页 > 其他好文 > 详细

re:从零开始的数位dp

时间:2018-09-11 19:43:14      阅读:162      评论:0      收藏:0      [点我收藏+]

标签:hide   通过   决定   mes   表示   理解   alt   9.1   bsp   

起源:唔,,前几天打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

标签:hide   通过   决定   mes   表示   理解   alt   9.1   bsp   

原文地址:https://www.cnblogs.com/MXang/p/9629526.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!