\(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 難 題意 用給定三角型填充六邊形 解法 此題的思...