1. 程式人生 > 其它 >FMT與子集卷積

FMT與子集卷積

技術標籤:重要推式子

FMT與子集卷積

C x = ∑ i ⋃ j = x a i ∗ b j C_x = \sum_{i\bigcup j = x}a_i*b_j Cx=ij=xaibj

sol.

構造一個 F M T ( A ) = ∑ i ⊂ x a i FMT(A) = \sum_{i\subset x}a_i FMT(A)=ixai
F M T x ( A ) ∗ F M T x ( B ) = ∑ k ⊂ x ∑ i ⋃ j = k a i ∗ b j = ∑ k ⊂ x C k = F M T x ( C ) FMT_x(A) * FMT_x(B) = \sum_{k \subset x}\sum_{i \bigcup j = k}a_i*b_j\\ =\sum_{k \subset x}C_k\\ = FMT_x(C)

FMTx(A)FMTx(B)=kxij=kaibj=kxCk=FMTx(C)


考慮如何快速構造這個 F M T ( A ) FMT(A) FMT(A)


很顯然的一個事情 F M T ( A ) = F M T ( A 0 ) + F M T ( A 1 ) [ 用 二 進 制 表 示 集 合 , 分 別 有 沒 由 前 面 的 第 一 個 元 素 ] FMT(A) = FMT(A_0) + FMT(A1) [用二進位制表示集合,分別有沒由前面的第一個元素] FMT(A)=FMT(A0)+FMT(A1)[]

那麼可以直接二進位制倍增來寫。。。

for(int len = 2 ; len <= n ; len = (len << 1)){
    for(int i = 0 ; i <= n ; i = i + len){
        for(int j = 0 ; j < (len >> 1) ; j++){
            f[i + j + (len >> 1)] += f[i + j];
        }
    }
}

大概就像這樣就可以了

逆FMT的話如下

for(int len = 2 ; len <= n ; len = (len << 1)){
    for(int i = 0 ; i <= n ; i = i + len){
        for(int j = 0 ; j < (len >> 1) ; j++){
            f[i + j] -= f[i + j + (len >> 1)];
        }
    }
}

就可以做掉了。。。。

FWT是這個玩意的加強版,專門來處理二進位制操作卷積的

o r or or卷積,就是上面的FMT

a n d and and卷積:

需要構造一個 F M T ( A ) FMT(A) FMT(A)使得, F W T ( A ) x ∗ F W T ( B ) x = F W T ( C ) x FWT(A)_x * FWT(B)_x = FWT(C)_x FWT(A)xFWT(B)x=FWT(C)x

即:
∑ i & x = x a i ∗ ∑ j & x = x b j = ∑ ( i & j ) & x = x a i ∗ b j = ∑ i & x = x c i \sum_{i \& x = x}a_i* \sum _ {j \& x = x}b_j = \sum_{(i \& j) \& x = x}a_i * b_j = \sum_{i \& x = x}c_i i&x=xaij&x=xbj=(i&j)&x=xaibj=i&x=xci

所以需要構造出:
F W T x ( A ) = ∑ i & x = x a i FWT_x(A) = \sum_{i \& x = x}a_i FWTx(A)=i&x=xai

FWT1

大概就是這樣

for(int len = 2 ; len <= n ; len = (len << 1)){
    for(int i = 0 ; i <= n ; i = i + len){
        for(int j = 0 ; j < (len >> 1) ; j++){
            f[i + j] = f[i + j] + f[i + j + (len >> 1)];
        }
    }
}

xor卷積:

需要構造一個 F M T ( A ) FMT(A) FMT(A)使得, F W T ( A ) x ∗ F W T ( B ) x = F W T ( C ) x FWT(A)_x * FWT(B)_x = FWT(C)_x FWT(A)xFWT(B)x=FWT(C)x


∑ i x o r x = x a i ∑ j x o r x = x b j = \sum_{i \ xor\ x\ =\ x}a_i \sum_{j \ xor \ x \ = \ x}b_j = ixorx=xaijxorx=xbj=

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-Vgia3cKl-1613121592741)(C:\Users\Administrator\Desktop\筆記\FWT2.PNG)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-5jsO5avm-1613121592758)(C:\Users\Administrator\Desktop\筆記\FWT3.PNG)]

補一個證明
g ( x , j ) ∗ g ( x , k ) = ( − 1 ) ∣ j ⋂ x ∣ + ∣ k ⋂ x ∣ = ( − 1 ) ( j x o r k ) ⋂ x g(x,j) * g(x , k) = (-1)^{|j\bigcap x| + |k\bigcap x|} = (-1)^{(j \ xor \ k) \bigcap x} g(x,j)g(x,k)=(1)jx+kx=(1)(jxork)x
很顯然的東西吖。。。。

所以就有程式碼

for(int len = 2 ; len <= n ; len = (len << 1)){
    for(int i = 0 ; i <= n ; i += len){
        for(int j = 0 ; j < (len << 1) ; j++){
            int A = f[i + j] , B = f[i + j + k];
            f[i + j] = A + B;
            f[i + j + k] = A - B;
        }
    }
}

很顯然的吧

逆的話,程式碼如下

for(int len = 2 ; len <= n ; len = (len << 1)){
    for(int i = 0 ; i <= n ; i += len){
        for(int j = 0 ; j < (len << 1) ; j++){
            int A = f[i + j] , B = f[i + j + k];
            f[i + j] = (A + B) / 2;
            f[i + j + k] = (A - B) / 2;
        }
    }
}

FWT可以用來做一些高維字首和的問題

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-ibOaQY33-1613121592772)(C:\Users\Administrator\Desktop\筆記\FWT4.PNG)]

很顯然就是 A L L = ∑ ( − 1 ) ∣ 與 n o w 相 關 的 維 度 ∣ a n o w ALL = \sum (-1)^{|與now相關的維度|}a_{now} ALL=(1)nowanow

與上面異或的定義 g ( x , i ) g(x,i) g(x,i)非常的相似(實際上就是同一個玩意)

實際上就是一個xor卷積的事情。。。。

入門題:luoguP3175 [HAOI2015]按位或

很容易列出方程
f [ i ] = ∑ j ∑ ( k ∣ j ) = i ( f [ k ] + 1 ) ∗ p [ j ] f [ i ] = ∑ j ! = i ∑ ( k ∣ j ) = i ( f [ k ] + 1 ) ∗ p [ j ] + ∑ k ∣ i = i ( f [ i ] + 1 ) ∗ p [ k ] f [ i ] = ∑ j ! = i ∑ ( k ∣ j ) = i ( f [ k ] + 1 ) ∗ p [ j ] + ∑ k ∣ i = i p [ k ] 1 − ∑ k ∣ i = i p [ k ] f[i] = \sum_{j}\sum_{(k|j) \ =\ i}(f[k] + 1) * p[j]\\ f[i] = \sum_{j != i}\sum_{(k|j) \ =\ i}(f[k] + 1) * p[j] + \sum_{k | i\ =\ i}(f[i] + 1) * p[k]\\ f[i] = \frac {\sum_{j != i}\sum_{(k|j) \ =\ i}(f[k] + 1) * p[j] + \sum_{k | i\ =\ i}p[k]} {1 - \sum_{k | i\ =\ i}p[k]} f[i]=j(kj)=i(f[k]+1)p[j]f[i]=j!=i(kj)=i(f[k]+1)p[j]+ki=i(f[i]+1)p[k]f[i]=1ki=ip[k]j!=i(kj)=i(f[k]+1)p[j]+ki=ip[k]

s o l 1. 解 決 分 母 的 快 速 計 算 , 直 接 對 { p } 做 一 個 f w t 就 好 了 , s o l 2. 分 子 第 二 項 同 s o l 1. s o l 3. 分 子 第 一 項 最 爛 每 一 次 都 要 做 一 個 F W T O ( 2 n ∗ 2 n ∗ n ) sol1.解決分母的快速計算,直接對\{p\}做一個fwt就好了,\\ sol2.分子第二項同sol1.\\ sol3.分子第一項最爛每一次都要做一個FWT\\ O(2^n * 2 ^ n * n) sol1.{p}fwtsol2.sol1.sol3.FWTO(2n2nn)
很顯然是不行的吧。。。

本人只能想到這種。。。

如果能做到動態維護 FWT卷積的話,這個式子還是很好做的。。。

。。。。

正解是 min-max容斥。。。。

我先去補一下二項式反演的坑

就好了,\
sol2.分子第二項同sol1.\
sol3.分子第一項最爛每一次都要做一個FWT\
O(2^n * 2 ^ n * n)
$$
很顯然是不行的吧。。。

本人只能想到這種。。。

如果能做到動態維護 FWT卷積的話,這個式子還是很好做的。。。

。。。。

正解是 min-max容斥。。。。

我先去補一下二項式反演的坑