數字dp筆記

2021-09-14 07:16:07 字數 3684 閱讀 7388

``我太菜了。

放幾個例題慢慢品。

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這本質上不還是記憶化搜...