今天是集訓的第一階段的結束。
第一階段 是以DP入門爲主。因爲智力真的有限,學長介紹了那麼多的DP實在有點接受不了,所有這幾天一直在搞數位DP。
先談一些我的理解,在我看來,數位dp就是一種優雅的暴力。
數位DP是一類計數問題。
具體題目大體以,統計一個區間【L,R】內,滿足條件的數有多少個。
數位dp特徵:一般L,R都會取1e9~1e18之間的數。
因爲只是入門,所以大體介紹一下。
在我看來,數位dp有三種解決方法。
一.DFS記憶化搜索
這應該是最常見的解決方法了,對狀態進行搜索。DFS搜索進行排除不合意的條件。
通常都會有模板。(偷自一位dalao的博客)
int dfs(int i, int s, bool e) {
if (i==-1) return s==target_s;
if (!e && ~f[i][s]) return f[i][s];
int res = 0;
int u = e?num[i]:9;
for (int d = first?1:0; d <= u; ++d)
res += dfs(i-1, new_s(s, d), e&&d==u);
return e?res:f[i][s]=res;
}
其中:
f爲記憶化數組;
i爲當前處理串的第i位(權重表示法,也即後面剩下i+1位待填數);
s爲之前數字的狀態(如果要求後面的數滿足什麼狀態,也可以再記一個目標狀態t之類,for的時候枚舉下t);
e表示之前的數是否是上界的前綴(即後面的數能否任意填)。
for循環枚舉數字時,要注意是否能枚舉0,以及0對於狀態的影響,有的題目前導0和中間的0是等價的,但有的不是,對於後者可以在dfs時再加一個狀態變量z,表示前面是否全部是前導0,也可以看是否是首位,然後外面統計時候枚舉一下位數。It depends.
於是關鍵就在怎麼設計狀態。當然做多了之後狀態一眼就可以瞄出來。
博客地址:http://www.cnblogs.com/jffifa/archive/2012/08/17/2644847.html二.預處理區間
先對所有的特徵片段區間進行篩查,排除不可能或者可能的情況,用數組保存
然後將n進行分解,利用for循環進行判斷,得出正確結論
三.強行DP數組暴力
來自我學長的代碼的啓示,利用幾層for循環進行暴力。。(只是對比前兩種方法得出的結論)
可能這麼說有點吃力也不好懂。。畢竟是一隻萌萌的菜雞。結合具體題目來寫吧