動態規劃專題(三)——數位DP
阿新 • • 發佈:2018-12-13
前言
數位 真的是最噁心的。
簡介
看到那種給你兩個數,讓你求這兩個數之間符合條件的數的個數,且這兩個數非常大,這樣的題目一般就是 數位 題。
數位一般都用於計數。
具體實現
數位有兩種實現方法:預處理+亂搞求答案以及記憶化搜尋。
個人感覺用記憶化搜尋來實現要比較容易一些(第一種做法我是真的不會)。
數位在求解的過程中運用了字首和的思想,即要求範圍內的解的個數,就相當於用範圍內的解的個數減去範圍內解的個數即可。
模板
貼一波記憶化搜尋
class Class_DigitalDP//數位DP(記憶化搜尋實現)
{
private:
#define Size 15//如果是int範圍內,數字長度不會超過15,這個Size要視題目而定
int len,num[Size],f[Size][10];//len儲存數字長度,num記錄數字的每一位,f則用於記憶化
inline void Init(LL x) {len=0;while(x) num[++len]=x%10,x/=10;num[len+1]=0;}//初始化,將x這個數字按位儲存下來
inline int dfs(int x,int s,int flag)//x記錄剩餘的位數,s記錄當前的狀態,flag記錄當前是否肯定在求解的範圍內(0表示不一定,1表示一定)
{
register int i,lim=9,w=0;//w用於統計答案
if(!x) return OK(s);//如果剩餘位數為0,就判斷當前狀態是否滿足條件,並退出函式
if(flag&&~f[x][s]) return f[x][s];//如果當前狀態肯定在求解範圍內,且已訪問並求解過當前狀態,就返回曾經求解出的答案
if(!flag) (Right(num[x])&&(w+=dfs(x-1,GetStatus(s,num[x]),0),0),lim=num[x]-1;//如果不保證在求解範圍內,則對這一位上的最大值單獨處理,並仍不能保證在求解範圍內
for(i=0;i<=lim;++i) if(Right(i)) w+=dfs(x-1,GetStatus(s,i),1);//列舉每一個數字,如果這個數字符合條件,就繼續搜尋
if(flag) f[x][s]=w;//如果當前狀態肯定在求解的範圍內,就將求解出的答案記錄下來,實現記憶化
return w;//返回答案
}
public:
Class_DigitalDP() {for(register int i=0,j;i<Size;++i) for(j=0;j<9;++j) f[i][j]=-1;}//初始化f陣列為-1
inline int GetAns(int x) {return (void)(Init(x)),dfs(len,0,0);}//將這個數按位儲存下來,然後記憶化搜尋求解
}DigitalDP;
幾道例題
照常貼幾道例題:
一道二進位制的數位,可以發現用預處理得到的是一個楊輝三角形… …
比較經典的數位題,關鍵在於要判前導。
應該是這幾道題裡我唯一一道寫記憶化搜尋的,需要加上一點噁心的數學轉化。