【專題】數位DP(按位DP)
阿新 • • 發佈:2019-02-10
之前說過要做個專題,雖然隔了好長時間。。但說話還是算數的,把之前做的ppt翻出來貼上,好吧,我就是懶。。
(回頭看看,良心發現,再補全些。。)
見識的還是少,歡迎討論啊~~
數位DP
•問題:在給定區間[A,B]內,找滿足要求的數。
•要求一般和數大小無關,而與數的組成有關
•例如,遞增的,1234,2579…
•雙峰的,19280,26193…
•含49的,49, 149, 1492…
•整除13的,26, 39…
•麻煩在於,規模大,位數>100,不能列舉。
•並且區間往往不是整百整千,需要小心處理邊界
•注意
–記憶化搜尋思路清晰
–開適當空間(能省則省)
–尋找合適的狀態,簡化計算量
•-表示數字從左到右相等
•例如:
•/-\
•1221,123455543
•資料規模:
•A,B<=10^100
0..num[i],否則可以列舉0..9
例如 num[] = 157, 列舉到14*時,個位可以為0..9,但是列舉到15*時,個位只能為0..7
•儲存
•dfs(i,j,k,flag)
•設狀態與遞迴引數一致f[i][j][k][flag],表示當列舉到第i位的數,匹配str[j],前一位是k,是否達到上限(flag=true,false)時,滿足要求的數字個數。
•dfs的過程,相當於在填充f,f的空間O(100*10*10*2),則dfs的時間O(20000)
•2.前導0不算數,不能和符號串匹配。特判下即可
–如,-/,0003(X),0113
•3.1234 匹配//,會被算成倆個。特判下即可
•4. 個位放在f[0][…],或者說157要存成num[] = 751,且只記錄flag=false的值時,f與數A,B無關!可以反覆利用,對於有多組輸入樣例的問題速度更快
例hdu3886
•題目大意:給一定區間[A,B],一串由/,\,-組成的符號串。求滿足符號串的數字個數。 •/表示數字從左到右遞增 •\表示數字從左到右遞減分析
F(A,B) = F(B,0)-F(A-1,0) //區間[A,B]中符合要求的數量 = 區間[0,B]的 - 區間[0,A-1]的
因此只要考慮區間[0,num]的情況就好了
暴力+儲存= 記憶化搜尋
•暴力 •暴力列舉每一位(0..9),注意區間邊界;與符號的匹配。 •遞迴函式為 int dfs(i,j,k,flag) •表示 列舉第i位的數,匹配str[j],前一位是k,是否達到上限(flag=true,false), 返回此時符合要求的數量 •注意邊界,如果達到了上限則只能列舉實現
•1.空間優化,只需記錄flag=false時的值。因為flag=true的值只會計算一次,不是冗餘計算,不用記錄。 –(不一定要開和引數一樣的陣列,適當變換下,分成幾種情況開多個數組,可以節省下記憶體)其他型別
•整除13 •dfs(i, m,flag) •列舉第i位數,前面枚舉出的數模13的餘數m,是否到達上限flag •整除自身各位數CF55D •dfs(i, m,l, flag) •列舉第i位數,前面枚舉出的數模LCM(0..9),LCM(前面枚舉出的數),是否達到上限 •包含”49” •dfs(i, k,find, flag) •列舉第i位數,前一位是k,是否已包含”49”(find=true,false),是否達到上限 •分類討論:前一位是否為4,當前是否已包含“49”部分解題報告:(習慣寫在程式碼末尾...)
寫到後來發現這已經成了模板題了,遇到問題,不用想太仔細,直接套上模板,快速、簡單、準確。