前面
最近學了點數位DP,也碼了幾個題,寫點學習筆記
數位DP
數位DP就是在數位上進行DP,(個位,十位,百位之類的)
一般數位DP,都會讓求在某一區間內滿足某一種限定的數的數量。
DP的方式一般是DFS+記憶化。
狀態的話就是 , 表示第pos位狀態爲 的滿足題目限制的數量
對了…
一般我們在進行 之前要對枚舉上界進行分解,就是把各個位分離,這樣既容易記錄狀態,也容易判斷枚舉的範圍。
看一下代碼應該就理解的差不多了.
int solve(int x)
{
pos=0;//一定要記住啊每一次都要變成0,寫題的時候老是忘
while(x)
{
a[pos++]=x%10;//把各個位分離開
x/=10;
}
return dfs(pos-1,....,true);
}
下面說一下 的時候對於上界的控制:
我們在 裏對枚舉上界進行了拆分,
然後我們在 的時候設置一個 變量 來記錄上一次 是否到達的上一個位的上界,
如果到達了上一個位的上界,那我們在這一次 的時候最大就只能枚舉到這一位的上界
如果沒有到達上一個位的上界,那麼我們就可以一直枚舉到 ;
舉個例子:
假設我們枚舉的上界是 ,假如我們枚舉第一位也就是百位是 的話,那我們第二位也就是十位就只能枚舉到 是不是,如果大於 的話就會超過枚舉上界;相反,假如我們在枚舉第一位的時候百位小於 ,那麼我們第二位就可以在 之間任意枚舉了。因爲 顯然小於 .
對於上界的控制還需要注意的就是在開始 ,要把 設置成爲 ,這樣才能保證枚舉一直不超過上界。
然後是對於前導 的處理:
和上界控制差不多,對於前導 我們也是用一個 變量 來進行控制。
假若上一位是存在前導 且當前位又恰好選擇了 ,那麼 位 ;反之爲 ;
然後就是對於 的講解了:
//分別是枚舉的位數,狀態,是否到達枚舉上界,是否有前導0
int dfs(int pos,int S,int limit,int lead)
{
if(pos==-1) //因爲上面是從pos=0開始拆分的所以這個是搜索的結束
return 1;//對於返回:一般的題目中都是要對最後的狀態進行判斷,合法的話返回1,不合法的話返回0,做題多了也就瞭解套路了
if(dp[pos][S]==-1 && !limit && !lead) //對於沒有特殊情況的話,直接上記憶化搜索
return dp[pos][S];
int up=limit ? a[pos] : 9;//這裏是上界判斷
int ans=0;//記錄答案
for(int i=0;i<=up;i++)//開始枚舉當前位所選的數字
{
........//一般會有一些判斷
ans+=dfs(pos-1,S...,limit && i==up,lead && i==0);
//假若上一位到達了枚舉上界且這一位也是枚舉上界的話,那麼下一位也必須是枚舉上界,兩個條件缺一不可。
//lead是用來判斷前導0
}
if(!limit && !lead) //除去特殊情況,進行記憶化
dp[pos][S]=ans;
return ans; //返回
}
題目
學完數位 之後也碼了幾道題,在我的博客裏都有題解.(按照我做的順序給出)
1.不要62 —————— 題解
2.HDU4734——————題解
3.POJ3252——————題解
4.HDU3709——————題解