數字DP入門詳解 題目推薦

2022-03-13 04:43:02 字數 2623 閱讀 5187

\(update:2019-9-6\)

部落格裡某些東西沒有解釋清楚,完善了對應的解釋

在開始之前,我們先來看一道題——題目鏈結

題目要求,相鄰兩位的差大於等於2,那麼我們先來構造乙個試一試。

比如說\(15246\)這個數,我們先取第一位為\(1\),然後第二位是\(5\),\(5-1=4>2\)所以符合條件,第三位是\(2\),\(5-2=3>2\)符合條件,第四位是\(4\),\(4-2=2\)符合條件,第五位是\(6\),\(6-4=2\)符合條件,所以這個數使符合條件的。

那麼問題來了,如果我們乙個數乙個數的構造,複雜度顯然是有問題的,我們就需要對其進行優化。來看\(15246\)和\(96246\)這兩個數,他們都是符合規則的,而且它們後三位是相同的,那麼我們很容易可以聯想到,只要倒數第四位與\(2\)的差符合規則,那麼只要後三位是\(246\)就一定是符合規則的,也就是說我們根本不需要去重複判斷。

有沒有想到什麼熟悉的東西?沒錯,記憶化!從前往後構造,當後幾位已經被處理過,我們就可以直接使用,而不是重新判斷,大大節省了時間。那麼我們就可以用\(f[pos][pre]\)來記錄當前位為第\(pos\)位,上一位為數值為\(pre\),且不含前導零,沒有卡在最大值上時,能夠對答案產生的貢獻。

那麼判斷也就很簡單了,只需要列舉下一位,看和當前位的差是否滿足規則即可。題目又要求不含前導零,也就是除了\(0\)本身以外的任何數不准用\(0\)開頭,那麼從第一位開始,我們記錄有前導\(0\)當有一位不為\(0\)之後,把狀態記錄為不含前導零,前導零後的第乙個不為零位無任何限制。

那麼我們來看一下程式吧

#include#include#include#include#include#define ll long long

#define gc() getchar()

#define maxn 15

using namespace std;

inline ll read()

while(isdigit(p))

return f?-a:a;

}void write(ll a)

int x,y,d[maxn],l;

ll f[maxn][maxn];

ll dfs(int pos,int pre,bool limit,bool lead)

if(!limit&&!lead)f[pos][pre]=ans; //這裡有多種寫法,其實就是要求你把各種特殊狀態都記錄下來

return ans;

}ll solve(int k)

return dfs(l,0,1,1);

}int main()

下面我們再來看兩道題,一道是zjoi2010數字計數,另一道是cqoi2016的手機號碼

對於這兩道題,還是跟剛才一樣——先構造。

數字計數這道題就是要求統計每個數出現的次數,那麼我們只需要分開統計,每次只統計乙個數字,重複十次即可,需要記錄的特殊情況就是前導零還有邊界情況

下面是**(就不再附詳細解釋了)

#include#include#include#include#define ll long long

#define gc() getchar()

#define maxn 15

using namespace std;

inline ll read()

while(isdigit(p))

return f?-a:a;

}void write(ll a)

int l,d[maxn];

ll x,y,f[maxn][maxn];

ll dfs(int pos,int s,int x,bool limit,bool lead)

ll solve(ll k,int a)

return dfs(l,0,a,1,1);

}int main()

return 0;

}

那麼對於手機號碼這道題,需要記錄的特殊狀態就比較多了,分別是前導零,邊界情況,前兩位的數值以及是否出現8和是否出現4

那麼**還是大同小異,只是加了幾個判斷而已

#include#include#include#include#include#define ll long long

#define gc getchar

#define maxn 15

using namespace std;

inline ll read()

while(isdigit(p))

return f?-a:a;

}ll l,r;int d[maxn];

ll f[maxn][maxn][maxn][5][5][5][5];

ll dfs(int pos,int pre,int pre2,int limit,int c,int ba,int si)

inline ll solve(ll x)

return dfs(len,11,11,1,0,0,0);

}int main()

[haoi2010]計數

[ahoi2009]同類分布

那麼數字dp大概就是這個樣子,很簡單,也很明顯

如果這篇部落格對你的學習有些許幫助,不妨點個推薦吧

樹形DP入門題目推薦以及解析

今天惡補樹形dp,感覺海星。其實挺簡單的。介紹幾道例題,我會的。1.洛谷p1352 沒有上司的舞會 我的一篇題解 我們可以考慮每乙個節點都是有兩種情況。乙個是被邀請 另乙個是不會被邀請。前者後果就是子節點不可以被選擇 後者結果就是子節點可以被選擇。於是關係明確,狀態轉移方程為 dp root 0 s...

數字DP 入門學習詳解

數字dp是dp的一種,顧名思義,按每乙個數字來進行dp。題目的要求與乙個數字相關,並且它能通過每乙個數字來進行轉移。例題 求所有n nn位數中能被m mm整除的數的個數。一般的dp是多維的,首先會有一維表示的是當前到了第幾位,通常情況這一維可以使用滾動。其它的就是根據題目的實際要求了,如例題就需要一...

搜尋題目推薦及解題報告

搜尋題目推薦及解題報告 8.28更新 2008 06 28 14 31 以前的帖子要麼太分散,要麼太凌亂,故現在開始,對每乙個分類做乙個長期更新的彙總貼。格式說明 題目名後面列出個人此題的大致難度 對菜鳥而言 poj 1069 the bermuda 難 題意 用給定三角型填充六邊形 解法 此題的思...