我們比較了解的是有關多項式的乘法運算,對於下標為整數,下標運算為相加等於某個數的時候,我們有很優秀的fft做法。
但是遇到一些奇怪的卷積形式時,比如我們定義 $h = f * g$, $h_ = \sum\limits_^{} \sum\limits_^{} [l \cup r = s] f_ * g_$。
此時下標是乙個集合,運算為集合並的卷積,我們已知了 $f$ 和 $g$ ,需要快速算出 $h$。
最暴力的做法是 $o(2^)$ 分別列舉 $l$ 和 $r$,把答案加到 $h$ 中去,這樣複雜度是 $o(4^)$,不太行。
這時我們就要一種高效的演算法。求卷積可以用分治乘法,好像比較高妙,但我們要講的是另一種:快速莫比烏斯變換和反演。
模擬fft,fmt也需要先把 $f$ 和 $g$ 求點值,點值相乘後再插值回去,快速莫比烏斯變換就相當於點值,快速莫比烏斯反演就相當於插值。
具體證明:
於是問題就在於如何快速求出 $f$ 和 $g$ 莫比烏斯變換(反演)。
如果要暴力的話,可以直接列舉子集算出莫比烏斯變換(反演),這樣是 $o(3^)$,雖然比較優秀了,但複雜度還能更低。
我們考慮用遞推解決:
這樣我們就能在 $o(n * 2^)$ 快速求出 $f$ 的莫比烏斯變換了。(逆莫比烏斯變換同理)
於是我們就解決了集合並卷積的問題。
upd:
我們都知道第一層迴圈列舉集合,第二層迴圈列舉它為$1$的位,把去掉這個$1$的子集的答案加上去的做法是錯的。我們考慮兩個集合$s, t$,其中$t \in s$。$t$可能有多種路徑到達$s$,也就是存在多個$k, k \in s, t \in k$,這樣$t$就會被算多次。
這裡有乙個感性理解的方法,為什麼第一層列舉位第二層列舉集合是對的,也就是每乙個集合它的所有子集的貢獻只被算了一次。
我們假設$k_$為$t$並上第乙個和$s$不一樣的位,我們發現$t$的答案會先算到$k_$上,而對於其他的$k$,在$t$的答案算上來的時候自己的答案已經會先算上去了。
而對於逆莫比烏斯變換,如果理解了莫比烏斯變換後,其本質就是乙個容斥。
void fmt(int *a)
void ifmt(int *a)
(此處$n$為集合大小, $u = 2^n$)
接下來我們來繼續講一講子集卷積:
問題是已知 $f$ 和 $g$,我們想求出 $h = f * g$,其中 $h_ = \sum\limits_ f_ * g_$。
回顧剛剛的集合並卷積,子集卷積的條件比集合並卷積更苛刻,即 $l$ 和 $r$ 的集合應該不相交。
考慮集合並卷積合法當且僅當 $l \cap r = \varnothing$,我們可以在卷積時多加一維,維護集合的大小,如 $f_$ 表示集合中有 $i$ 個元素,集合表示為 $s$。可以發現當 $i$ 和 $s$ 的真實元素個數符合時才是對的。
初始時,我們只把 $f_$ 的值賦成原來的 $f_$($g$ 同理),然後對每乙個$f_i$做一遍fmt,點值相乘時這麼寫:$h_ = \sum\limits_^ f_ * g_$。最後掃一遍把不符合實際情況的狀態賦成 $0$即可。($bc$表示集合元素個數,即$bitcount$)
for i = 0to n
fmt(f[i])
fmt(g[i])
for s = 0 to u - 1
for j = 0
to i
h[i][s] += f[j][s] * g[i -j][s]
ifmt(h[i])
for s = 0 to u - 1
h[bc[s]][s]
is the real answer
莫比烏斯函式與莫比烏斯反演
1.1 莫比烏斯函式 莫比烏斯函式可以看做乙個輔助函式,它在莫比烏斯反演公式中用到。1.2 莫比烏斯反演 莫比烏斯反演公式是 根據和函式來求算數函式的乙個公式。1.3 算數函式 所有在正整數上運算的函式稱為算數函式。1.4 和函式 設 f 是算數函式,f 的和函式為n的所有約數的算數函式之和。1.5...
莫比烏斯反演 二 莫比烏斯反演定理
首先設兩個任意函式f x 和f x 定義運算 f x sum f d 這時就可以用f x 表示f x f 1 f 1 f 2 f 1 f 2 f 3 f 3 f 1 f 4 f 4 f 2 f 1 f 5 f 5 f 1 f 6 f 6 f 3 f 2 f 1 這時可以試著用f x 表示f x f ...
莫比烏斯變換 子集卷積
大佬 部落格 fwt與運算。其實就是這個的低配版本 用來快速計算子集卷積。就是說,f i g j h k j k i j k 0 f i sum f i g j h k j k i j k 0 打包運算。首先我們考慮它的低配版本。f i g j h k j k i f i sum f i g j h...