學習部落格:
戳這裡戳這裡
「在資訊學競賽中,有這樣一類問題:求給定區間中,滿足給定條件的某個d 進製數或
此類數的數量。所求的限定條件往往與數字有關,例如數字之和、指定數碼個數、數的大小
順序分組等等。題目給定的區間往往很大,無法採用樸素的方法求解。此時,我們就需要利
用數字的性質,設計log(n)級別複雜度的演算法。解決這類問題最基本的思想就是「逐位確定」
的方法。下面就讓我們通過幾道例題來具體了解一下這類問題及其思考方法。」——劉聰
事實上,為什麼會想到用數字dp來做,就是因為限定條件往往和數字有關,而仔細地樸素的暴力方法中,所做的重複的工作太多。這樣的條件會使得dp(記憶化搜尋)有用武之地。
比如如果我們要統計[0,54321]中滿足某個條件的個數,需要將其拆分為
[00000,09999][10000,19999],[20000,29999],[30000,39999],[40000,49999],
[50000,50999],[51000,51999],[52000,52999],[53000,53999],
[54000,54099],[54100,54199],[54200,54299],
[54300,54309],[54310,54319],
[54320,54321]
為什麼要這麼分呢?隨便舉個例子,如果我們統計過了[0000,9999]中的滿足條件(或者其他各種不滿足條件的狀態)的個數,那麼分別在加上字首,就可以判斷出有多少個滿足條件的個數。目的是為了將大的區間劃分為小的區間進行求解。
因此,總結一句話,數字dp減少的運算量為:前面幾位固定,後面幾位可以任意取的個數統計。
模板:
1 typedef longview codelong
ll;2
int a[20
];3 ll dp[20][state];//
不同題目狀態不同
4 ll dfs(int pos,/*
state變數
*/,bool lead/*
前導零*/,bool limit/*
數字上界變數
*/)//
不是每個題都要判斷前導零525
//計算完,記錄狀態
26if(!limit && !lead) dp[pos][state]=ans;
27/*
這裡對應上面的記憶化,在一定條件下時記錄,保證一致性,當然如果約束條件不需要考慮lead,這裡就是lead就完全不用考慮了
*/28
return
ans;29}
30ll solve(ll x)
3138
return dfs(pos-1
/*從最高位開始列舉
*/,/*
一系列狀態
*/,true,true);//
剛開始最高位都是有限制並且有前導零的,顯然比最高位還要高的一位視為0嘛39}
40int
main()
4148 }
練手題目1:戳這裡
題意:求1-n內有多少個數滿足各位之和整除該數。
解題思路:數字dp,列舉各位之和。
附ac**:
1 #include2 #include3 #include4 #includeview code5 #include
6using
namespace
std;
7 typedef long
long
ll;8
int a[22
];9 ll dp[20][220][220];//
不同題目狀態不同
10int
mod;
11 ll dfs(int pos, int state/*
state變數
*/, int r/*
其他記錄點,在這裡是餘數
*/, bool limit/*
數字上界變數*/)
1234
//計算完,記錄狀態
35if(!limit) dp[pos][state][r] =ans;
36/*
這裡對應上面的記憶化,在一定條件下時記錄,保證一致性,當然如果約束條件不需要考慮lead,這裡就是lead就完全不用考慮了
*/37
return
ans;38}
39ll solve(ll n)
4048 ll ans = 0;49
for(int i = 1; i <= 9 * pos; ++i)//
列舉模50
56return
ans;57}
58int
main()
5968
6970 }
練手題目2:戳這裡
題意:求l-r中有多少個數滿足各位》0的數不大於三個。
解題思路:模板題略作修改。
附ac**:
1 #include 2view codeusing
namespace
std;
3const
int maxn = 22
;4 typedef long
long
ll;5
inta[maxn];
6ll dp[maxn][maxn];
7 ll dfs(int pos, int stat, bool
lim)820
}21if(!lim && stat <= 3) dp[pos][stat] =ans;
22return
ans;23}
24ll solv(ll x)
2532
33return dfs(pos, 0, true
);34}35
intmain()
3646
return0;
47 }
數字DP入門 數字DP模板
數字dp是一種計數用的dp,一般就是要統計乙個區間 le,ri 內滿足一些條件數的個數。所謂數字dp,字面意思就是在數字上進行dp咯。數字還算是比較好聽的名字,數字的含義 乙個數有個位 十位 百位 千位.數的每一位就是數字啦!之所以要引入數字的概念完全就是為了dp。數字dp的實質就是換一種暴力列舉的...
數字dp 模板
dp pos,狀態變數.限制布林 if limit dp 狀態 a 已經求出對應狀態值下的結果了 記錄下來 return a 所以 數字dp其實就是一種求解有關於l到r有多少個符合條件的數目類似的統計問題的解題思路 一遍遍數字列舉太慢 不如我們根據條件列舉數字 數字dp本質上是記憶化搜尋 我們需要在...
數字DP模板
數字dp問題,大多是統計數量,通常用按位處理的方法解決。具體為 詢問 l,r l,r l,r 中滿足某一條件的數。利用字首和的思想,我們可以把問題簡化,即轉化為詢問 1,r 1,r 1,r 和 1,l 1 1,l 1 1,l 1 實現時,常常使用記憶化搜尋,由於有很多限制條件,所以常常增加幾維狀態,...