``我太菜了。
放幾個例題慢慢品。
1.不要62
題意:輸出一段區間上不出現62和4的數字總個數
#include
using nemespace std;
intini
(int x)
//存個數字,位數為k
//一開始看的是最高位,所以初始是達到上限的
//一開始那個數字沒有上一位,所以if6是0啦
return
dfs(k,0,
1);}
//len是當前的位置,也就是數字長度,在後續dfs中逐漸減到0;if6的意思是該數的上一位是否為6
//maxn是判斷上限是否達到,即搜尋時最高位不是9,而是它最初給的那個值
//比如765,最高位搜不到9只能到7
intdfs
(int len,bool if6,bool maxn)
//這個更新 別忘了條件啊!!!是不斷在更新的,我服了我自己了。老是錯
return maxn ? cnt:dp[len]
[if6]
=cnt;
}int
main()
}
2.b數。
含有13且能被13整除的叫b…數
我對dp真的是一無所知,這裡有兩個判斷條件,所以dp要開兩重
還看到一種四維dp的(dp[len][mod][if13][pre])判13需要存兩個資料
注意dp陣列大小,找錯找到懷疑人生。
int
dfs(
int len,
int sta,
int yu,
int maxn)
int cnt =0;
int lim = maxn ? num[len]:9
;if(!maxn &&
~dp[len]
[sta]
[yu]
)return dp[len]
[sta]
[yu]
;for
(int i =
0;i <= lim;i++)if
(!maxn) dp[len]
[sta]
[yu]
= cnt;
return cnt;
}
3.windy數
就是求相鄰數字絕對值差小於2的數的個數,注意輸入資料中含有前導零的項。
dfs的時候得處理一下。(處理一次就ok了其實,看起來挺複雜滴)
不知道直接讀string再處理會不會簡單一些啊
dp[i][j]陣列長度為i,最高為為j時的數字個數
法(一) dfs
long
long
dfs(
int len,
int pre, bool f, bool maxn)
if(len <=0)
int cnt =0;
for(
int i =
0;i <= lim;i++
)//沒有前驅 正常操作
elseif(
abs(i - pre)
>=
2) cnt +
=dfs
(len -
1, i,
1, i == lim && maxn);}
//如果未達到上限且沒有前驅,值得記錄if(
!maxn && f) dp[len]
[pre]
= cnt;
return cnt;
}
那麼我們dfs預設是存在前導0的。dfs(len,0,0,1)–dfs(當前長度,前乙個數字,合法否,上限否)
法(二)dp計算
分情況討論 比如數 96758
ans = 位數小於5時的所有情況 + 位數等於5但首位小於9的所有情況 + 位數等於5且首位9後面的情況
dp[5][9] = dp[1-4][1-9]+dp[5][1-8]+討論
第三塊的討論nie
首先首位為9 討論第二位1-6都行 那麼ans+=dp[6所在位數][1-9]
看看第三位 啊 如果還要一樣的話就不滿足條件了 所以我們到此為止。。討論結束
同理,就是一位一位的覆蓋逼近原數,一旦不滿足條件就退出迴圈。
初始化 吶 位數為1的dp都是1
然後列舉初始化 三個for注意迴圈順序
0:初始化
void
ini(
)//從二位起,列舉。
for(
int i =
2;i <=
10;i++)}
}}}
情況1 位數相同,首位不同
for
(int i =
1;i <= num[k]-1
;i++
)
情況2 位數比現在小,首位隨便亂來(x
for
(int i = k -
1;i >=
1;i--
)}
情況3 位數同,首位同,一位一位找
for
(int i = k -
1;i >=
1;i--)}
//跳出條件if(
abs(num[i]
- num[i +1]
)<2)
break
;}
3.round numbers
要求換成二進位制後的裡面0的個數大於等於1
法一 組合數學
法二 dp
哇 看了這麼多題終於自己做出來了一道。。
//主要是處理前導0的問題 乙個資料也就處理一次 以及注意dp陣列大小,我這個缺心眼的又爆了一次。
intdfs
(int len,
int o,
int z,bool f,
int maxn)
else cnt +
=dfs
(len -1,
0,0,
0, maxn&&i == lim);}
//常規操作
else}if
(!maxn) dp[len]
[o][z]
= cnt;
return cnt;
}
4.f(x)
題意:每位加權2^(len)次方 求0-y範圍內小於x的個數
有乙個奇妙的操作,就是求差。
吶,為什麼不能求和呢?要判斷sum<=f(x),如果要用dp那麼要開dp[len][sum][f(x)]
會爆。so 我們求差,求差的好處,len層層遞減,從dp[len][f(x)]算下去
若要二維dp求和,那麼就變成dp[len][0]算上來 那樣後面的還沒初始化就被參與了運算,dp失敗。。
所以想要求和,得開三維,從最外層開始算(碼一下,慢慢研究,一知半解來的
int
dfs(
int len,
int sum,bool maxn)if(
!maxn) dp[len]
[sum]
= cnt;
return cnt;
}
數字dp筆記
數字dp 一 問題簡介 與數字有關的區間統計問題 例 求給定區間中,滿足給定條件的某個d進製數的數量,而限定條件往往與數字有關,比如數字之和,制定數碼個數,數的大小分組等 基本思想 逐位確定,預處理 二 通用狀態 1.預處理,從高位到低位列舉當前數字第一次小於n的那一位,這樣的話,之前的位數都已經確...
數字dp學習筆記
我們通常使用字首和的思想和記憶化搜尋來實現數字 dp。就是上面所說的常見問法。例題 windy 數 int dfs int k,int x,int p,int q if p q f k x res return res 這道題的難點就在於對相鄰兩個數字之差至少為 2 的處理,我們一開始將 x 設為 ...
演算法筆記 數字dp
前言 當我們遇到某些題目的時候 比如像讓你統計l r這乙個區間內的數字和以及滿足條件的數有幾個這一類的題目 常常會因為區間太大而無法計算。這時候,我們就需要用上我們偉大的數字dp啦 數字dp的實質就是換一種暴力列舉的方式,使得新的列舉方式滿足dp的性質,然後記憶化就可以了。nm這本質上不還是記憶化搜...