數位dp 筆記

數位dp 筆記

數位dp一直是個人弱項,惦記很久了,最近補了補,感受還行。ubuntu

解決的問題 & 主體思想

解決一個區間中,知足某些條件(與每一位有關)的數的數量(或者帶權的和)。spa

作法:考慮求前綴 \([1,x]\) 的答案。code

若是你是新手,請先考慮一下大概要怎麼作,再繼續看字符串

先把位(不必定是十進制)拆開來,而後是一個形如 "dp到第 \(i\) 位,..." 的 dp,通常能夠用記憶化搜索,一位一位的填,使得它看起來友好一些(我的感受這樣可讀性好)。get

而後要解決 \(\le x\) 的限制。每次按照這樣的規則來填數字:it

  • 默認每一位都不能超過 \(x\) 對應的位
  • 若是有一位小於了 \(x\) 對應的位,則後面就沒限制了

這個很好理解。好比說如今欽點下來是 \(123***\)\(x=123456\),那後面顯然不能超過 \(456\)入門

而若是如今欽點下來是 \(122***\),那它就算是 \(122999\),也不會超過 \(x\)ast

用一個 lim 標記維護當前是否卡到上界。注意它應該被記在 dp 狀態裏。class

入門 —— windy數

求區間知足:任意相鄰兩位的差都不超過 \(2\) 的數,的數量。擴展

dp 狀態:到第幾位,當前選了什麼(以決定下一個可不能夠選),lim

而後每次 dfs 擴展的時候,判斷一下下一個填的是否合法,再加個記憶化,就好了。

代碼

繞一個彎 —— 萌數

求區間知足:將數當作字符串,沒有任何長度 \(\ge 2\) 的迴文串的數,的數量。

沒有任何長度 \(\ge 2\) 迴文串 \(\rightarrow\) 任意一個字符和它前面一個,兩個都不一樣。

這樣就保證了沒有長度等於 \(2,3\) 的迴文串,而後其他的迴文串都是由這兩種擴展出來的,天然也沒有了。

剩下就很好 dp 了,和上一個差很少。

代碼

the end? —— 恨7不成妻

hdu的題,我第一次學數位dp的時候被老師稱做「畢業題」

你要能把這個題寫出來,你數位dp就差很少了

當時看着老師標程打的,如今簡單複習了一下,發現還挺好想的 而後把它秒了,其實就是一個傻逼縫合怪題

要知足三個條件:

  • 不能有數位7
  • 數位和不能是7的倍數
  • 數自己不能是7的倍數

區間求知足條件平方和。

這裏涉及到一個帶權求和。帶權求和狀態要變一下,表示從這位開始截取,的帶權和。

好比說 \(x=123\),填好了 \(11*\),知足條件的數有 \(111\)\(113\)\(114\)\(116\)\(118\)

帶權和爲 \(1^2+3^2+4^2+6^2+8^2=126\)

爲何要作一步截取呢?由於要方便轉移。考慮轉移,至關於,我先肯定好後面若干位,在它們的前面都填上相同的數字(這裏至關於放上了 \(1\)

而後填相同的數字能夠看作是加法 (這裏至關於 \(+10\)

而後平方和,總體加,好作吧:再維護數量和一次方和,設爲 dp[...][0/1/2],對應數量,和,平方和

設如今總體加的爲 \(a\),後面一位的 dp[...][0/1/2] 記下來爲 nex[0/1/2],如今的是 cur[0/1/2],則有:

cur[0]+=nex[0];
cur[1]+=nex[1]+nex[0]*a;
cur[2]+=nex[2]+2*nex[1]*a+nex[0]*a*a

(就是拆括號搞一下就行)

對於條件:

  • 每次不填 \(7\)
  • 記錄數位和對 \(7\) 的餘數,放在狀態裏,取 \(0\) 那個狀態
  • 記錄整個數對 \(7\) 的餘數,放在狀態裏,取 \(0\) 那個狀態

代碼

當心細節 [SDOI2016]儲能表

\(\sum\limits_{i=0}^{n-1} \sum\limits_{j=0}^{m-1} \max(i\oplus j-k,0)\)

\(n,m,k\le 10^{18}\)

後面等價成 \(>k\) 的和,減去 \(>k\) 的數量乘以 \(k\)

拆成二進制,作數位 \(dp\)。記下三個 lim,表示是否卡在 \(n\) 的上界,\(m\) 的上界,\(k\) 的下界 (由於 \(k\) 那邊是個 \(>\) 的限制)

而後上一題相似的求一下帶權和就好了,要維護一下數量和總和。

代碼

複雜度起飛 [AHOI2009]同類分佈

因爲數位 dp 的基本模型只有一個 log,因此能夠帶不少別的

題意:求區間能整除數位和的數的數量

好比 \(12\) 就知足條件由於 \(1+2\)\(12\) 的倍數

\(x\le 10^{18}\)

注意到數位和不會超過 \(9\times 18=162\)

先枚舉數位和 \(k\),而後 dp 裏設兩維,一維表示當前數位和,一維表示當前數模 \(k\) 的餘數。最後取答案就是 \(\%k=0\),數位和 \(=k\) 的那個狀態

複雜度是 \((9\times \log n^3)\log n\),很是暴力

代碼

相關文章
相關標籤/搜索