# FMT 和 子集卷积

## FMT

for( i in 0 to n-1 )
for( j in 0 to 2^n-1)
if( j & ( 1 << i ) )
a[j] += a[j ^ ( 1 << i )]


for( i in n-1 downTo 0 )
for( j in 2^n - 1 downTo 0)
if( j & ( 1 << i ) )
a[j] -= a[j ^ ( 1 << i )]


for( i in 0 to n-1 )
for( j in 0 to 2^n-1)
if( j & ( 1 << i ) )
a[j] -= a[j ^ ( 1 << i )]


FMT 可以写成 FFT 那样的形式，就不赘述了。

## 或卷积

$C_s = \sum_{i|j=s} A_i B_j$

\begin{aligned} \ [x]FMT(C) &=\sum_{s \sube x}C_s\\ &= \sum_{s \sube x}\sum_{i|j = s}A_iB_j\\ &= \sum_{i|j \sube x} A_iB_j\\ &= ( \sum_{i\sube x} A_i )(\sum_{j\sube x} B_j)\\ &= [x]FMT(A) \cdot [x]FMT(B) \end{aligned}

## 子集卷积

$C_s = A\times_{subset} B = \sum_{i|j=s,i\&j = 0} A_i B_j$

$(i|j = s) , (i\&j = 0) \Leftrightarrow i|j = s , p(i)+p(j) = p(s)\\C_s = \sum_{i|j = s , p(i)+p(j) = p(s)} A_iB_j$

$C'_{x,s} = \sum_{i|j = s,p(i)+p(j) = x} A_iB_j[p(s) = x]$

A'_{x,s} = \left\{\begin{aligned}&0 & {p(s) \neq x}\\&A_{s} & {p(s) = x} \end{aligned}\right.

$C'_{x,s} = \sum_{i|j = s,p(i)+p(j) = x} A'_{p(i),i} B'_{p(j),j}$

\begin{aligned}C'_{x} &= \sum_i IFMT(FMT(A'_i) · FMT(B'_{x-i}))\\&= IFMT( \sum_i FMT(A_i') · FMT(B_{x-i}') )\end{aligned}

#include "iostream"
#include "algorithm"
#include "cstring"
#include "cstdio"
using namespace std;
#define P 1000000009
int rd( ) {
char ch = ' '; int ret = 0;
while( ch > '9' || ch < '0' ) ch = getchar();
while( ch >= '0' && ch <= '9' ) ret = ret * 10 + ch - '0' , ch = getchar();
return ret;
}

int A[1<<21] , B[1<<21] , n , len;
int a[21][1<<21] , b[21][1<<21] , c[21][1<<21];

void FMT( int A[] , int l ) {
for( int i = 0 ; i < l ; ++ i )
for( int j = 0 ; j < ( 1 << l ) ; ++ j )
if( j & ( 1 << i ) ) A[j] = ( A[j] + A[j ^ ( 1 << i )] ) % P;
}
void IFMT( int A[] , int l ) {
for( int i = 0 ; i < l ; ++ i )
for( int j = 0 ; j < ( 1 << l ) ; ++ j )
if( j & ( 1 << i ) ) A[j] = ( A[j] + P - A[j ^ ( 1 << i )] ) % P;
}

int main() {
cin >> n; len = ( 1 << n );
for( int i = 0 ; i < len ; ++ i ) A[i] = rd() , a[__builtin_popcount(i)][i] = A[i];
for( int i = 0 ; i < len ; ++ i ) B[i] = rd() , b[__builtin_popcount(i)][i] = B[i];
for( int i = 0 ; i <= n ; ++ i ) FMT( a[i] , n ) ,  FMT( b[i] , n );
for( int x = 0 ; x <= n ; ++ x ) {
for( int i = 0 ; i <= x ; ++ i )
for( int j = 0 ; j < ( 1 << n ) ; ++ j )
( c[x][j] += 1ll * a[i][j] * b[x - i][j] % P ) %= P;
IFMT( c[x] , n );
}
for( int i = 0 ; i < len ; ++ i ) printf("%d ",c[__builtin_popcount(i)][i]);
}

posted @ 2020-02-29 23:40  yijan  阅读(1083)  评论(0编辑  收藏  举报