SOS DP學習筆記

2022-08-18 18:36:08 字數 1374 閱讀 3159

sum over subsets(sos) dp

給出乙個長度為\(2^n\)的陣列\(a\),對於每乙個\(mask< 2^n\)要求計算出\(f[mask]=\sum_a[sub]\)

(其中\(sub\in mask\)表示\(sub\&mask=sub\))

1.暴力

for(int mask = 0; mask < (1根據定義直接做,列舉所有小於\(mask\)的集合,判斷\(sub\)是否是\(mask\)的子集

複雜度\(o(4^n)\)

2.子集列舉

for(int mask = 0; mask < (1子集列舉優化之後

總複雜度是\(\sum_^c(n,m)\cdot 2^m = \sum_^c(n,m)\cdot 2^m\cdot 1^=(1+2)^n\)

複雜度\(o(3^n)\)

3.sosdp

考慮在計算當前的狀態的\(f[mask]\)的時候,能否利用之前計算的結果來優化複雜度,並且不會重複計算

那就要定義新的狀態:\(f[mask][bit]\)表示對於集合\(mask\),在子集\(sub\)和\(mask\)只有最後\(bit\)位存在不同的情況下的答案

可以發現\(f[mask][bit]= \begin a[mask] & bit=-1 \\ f[mask][bit-1] & mask\&(1<

當前位是\(1\)的情況下有兩個分支,這個位置是\(1\)或者\(0\),並且從只改變之後的位的狀態轉移過來,能保證不重複

當前位是\(0\)的情況下這個位不能改變,所以只能選這位是\(0\)的之後的狀態轉換過來

空間壓縮一下,**如下

for(int mask = 0; mask < (1<複雜度\(o(n2^n)\)考慮一下如何計算\(f[sub]=\sum_ a[mask]\)

可以發現把所有集合取反,\(f[\overline] = \sum_\in \overline}a[\overline]\)

就相當於把\(0\)變成\(1\)來處理,**基本相同

for(int mask = 0; mask < (1

**codeforces383e

sosdp(高維字首和)學習筆記

我們先看一維字首和 for int i 1 i n i s i s i 1 那麼二維字首和 for int i 1 i n i for int j 1 j n j s i j s i 1 j s i j 1 s i 1 j 1 這個是根據容斥計算的,維度很高的時候就不行了 我們換一種方法 for i...

演算法模板 SOS DP

sos dp text 是用來解決這樣的問題的 其實就是子集和dp。上面每個 f mask 裡面包含了 mask 所有二進位制子集的資訊。這是一種 n log 2 n 的dp方法。我們定義乙個dp狀態 s mask,i 代表 mask 子集中只有最靠右的 i 位與其不同的狀態。具體是這樣的 圖中描述...

sosdp 二進位制子集的貢獻

可以o n 2 n 算出n位每個mask值所包含子集的二進位製碼下標的貢獻 比如f 5 a 0 a 1 a 4 a 5 這種的,101包含了000,001,100,101 1 include2 pragma comment linker,stack 1024000000,1024000000 3 i...