數位dp


數位dp

定義

數位dp(Digit Entry DP)是一種計數用的dp,一般就是要哦統計區間[l,r]內滿足一些條件的數的個數。所謂數位dp,字面意思就是在數位上進行dp。數位的含義:一個數有個位、十位、百位、千位......數的每一位就是數位啦!

數位dp的思想

數位dp的實質就是換一種暴力枚舉的方式,使得新的枚舉方式滿足dp的性質,然后記憶化就可以了。

模板及例題

模板:

typedef long long ll;
int a[20];
ll dp[20][state];   //不同題目狀態不同
ll dfs(int pos,int state,bool lead,bool limit)       //變量,狀態,前導0,數位上界;注意不是每題都要判斷前導零
{
    if(pos==0) return 1;    //遞歸邊界,一般一種遞歸到結束只能產生一種情況
    if(!limit && !lead && dp[pos][state]!=-1) return dp[pos][state];    //記憶化
    int up=limit?a[pos]:9;  //枚舉上界
    ll ans=0;               //計數
    for(int i=0;i<=up;i++)  //枚舉,然后把不同情況的個數加到ans就可以了
    {
        if() ...
        else if()...        //一下條件
        ans+=dfs(pos-1,/*狀態轉移*/,lead && i==0,limit && i==a[pos]) //最后兩個變量傳參都是這樣寫的
        //state狀態轉移要保證i的合法性,比如不能有62,那么當pre==6&&i==2就不合法,這里用state記錄pre是否為6即可。
    }
    if(!limit && !lead) dp[pos][state]=ans;
    return ans;
}
ll solve(ll x)
{
    int tot=0;
    while(x)
    {
        a[++tot]=x%10;
        x/=10;
    }
    return dfs(tot/*從最高位開始枚舉*/,/*一系列狀態 */,true,true);//剛開始最高位都是有限制並且有前導零的,顯然比最高位還要高的一位視為0嘛
}
int main()
{
    ll le,ri;
    while(~scanf("%lld%lld",&le,&ri))
    {
        //初始化dp數組為-1,這里還有更加優美的優化,后面講
        printf("%lld\n",solve(ri)-solve(le-1));
    }
}

例題1:【不要62】(數位dp入門經典題)

描述:給定一個區間,不帶4以及沒有連續62的數字有多少個;

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
ll dp[20][2],arr[20];
ll dfs(int pos,int state,bool lead,bool limit)
{
    if(pos==0)  return 1;
    if(!limit && !lead && dp[pos][state]!=-1)   return dp[pos][state];
    int up = limit?arr[pos]:9;
    ll ans = 0;
    for(int i=0;i<=up;++i)
    {
        if(i==4)    continue;
        if(state && i==2)   continue;
        ans += dfs(pos-1,i == 6,lead && i==0,limit && i==arr[pos]);
    }
    if(!limit && !lead) dp[pos][state] = ans;
    return ans;
}
ll solve(int x)
{
    int tot = 0;
    while (x){
        arr[++tot]=x%10;
        x/=10;
    }
    return  dfs(tot,0,true,true); 
}

int main()
{
    int l,r;
    while(scanf("%d %d",&l, &r) && (l||r))
    {
        memset(dp,-1,sizeof(dp));
        printf("%lld\n",solve(r) - solve(l-1));
    }
    system("pasue");
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM