集合幂级数
定义
设全集为 \(U=\{ 0,2,\dots,n-1 \}\),设 \(F\) 为一个域,称 \(f:2^U \to F\) 为 \(F\) 上的一个集合幂级数。对于每个 \(S \subseteq 2^U\),记 \(f_S\) 为 \(S\) 代入 \(f\) 后的函数值,也称其为该集合幂级数的第 \(S\) 项系数。
用
来表示一个集合幂级数。
集合幂级数的加减法为对应系数的运算。
卷积
定义
定义一种运算 \(\ast\),使其满足交换律,结合律,存在单位元,使得:
这样定义还满足加法的分配律。
集合并卷积
取 \(L \ast R=L \cup R\),该卷积称为集合并卷积。若 \(h=fg\),则有:
定义 \(f\) 的莫比乌斯变换为:
本质为高维前缀和。
由容斥原理,定义 \(\hat f\) 的莫比乌斯反演为:
本质为高维差分。
代入集合并卷积的式子可以得到:
快速进行莫比乌斯变换和莫比乌斯反演后即可 \(O(n2^n)\) 计算集合并卷积。
void FWT_or(ll *a,int type)
{
for(int len=1;len<all;len<<=1)
for(int i=0;i<all;i+=len<<1)
for(int j=i;j<i+len;++j)
a[j+len]=(a[j+len]+a[j]*type)%p;
}
集合交卷积
取 \(L \ast R=L \cap R\),该卷积称为集合交卷积。若 \(h=fg\),则有:
定义 \(f\) 的莫比乌斯变换为:
本质为高维前缀和。
由容斥原理,定义 \(\hat f\) 的莫比乌斯反演为:
本质为高维差分。
代入集合交卷积的式子可以得到:
快速进行莫比乌斯变换和莫比乌斯反演后即可 \(O(n2^n)\) 计算集合交卷积。
void FWT_and(ll *a,int type)
{
for(int len=1;len<all;len<<=1)
for(int i=0;i<all;i+=len<<1)
for(int j=i;j<i+len;++j)
a[j]=(a[j]+a[j+len]*type)%p;
}
集合对称差卷积
取 \(L \ast R=L \oplus R\),该卷积称为集合对称差卷积。若 \(h=fg\),则有:
对于一个集合 \(S\),有:
当 \(S\) 为空集时,\((-1)^{|S \cap T|}\) 恒为 \(1\),等式成立。当 \(S\) 不为空集时,将 \((-1)^{|S \cap T|}\) 两两配对即可。
也可以枚举交集来证明:
代入集合对称差卷积的式子可以得到:
因此,定义 \(f\) 的沃尔什变换为:
得 \(\hat f\) 的沃尔什逆变换为:
那么对于集合对称差卷积就有 \(\hat h_S=\hat f_S\hat g_S\)。
\(|U|=n\) 的 \(FWT\) 本质为每一维长度为 \(2\) 的 \(n\) 维 \(FFT\)。
快速进行沃尔什变换和沃尔什逆变换后即可 \(O(n2^n)\) 计算集合对称差卷积。
void FWT_xor(ll *a,int type)
{
for(int len=1;len<all;len<<=1)
{
for(int i=0;i<all;i+=len<<1)
{
for(int j=i;j<i+len;++j)
{
ll x=a[j],y=a[j+len];
a[j]=(x+y)%p,a[j+len]=(x-y+p)%p;
if(type<0) a[j]=a[j]*inv%p,a[j+len]=a[j+len]*inv%p;
}
}
}
}
子集卷积
取 \(\ast\) 为不相交集合并,即当 \(A \cap B \ne \varnothing\) 时,\(A \ast B\) 未定义,即 \(x^Ax^B=0\),否则为 \(A \cup B\),称该卷积为子集卷积。若 \(h=fg\),则有:
注意到 \([L \cup R = S][L \cap R = \varnothing ]=[L \cup R = S][|L| + |R| =|S| ]\),因此定义 \(f\) 的集合占位幂级数 \(a\),满足 \(\forall i\ne |S|,a_{i,S}=0 \and a_{|S|,S}=f_S\),那么有:
也就是进行莫比乌斯变换后,对占位幂级数中的形式幂级数进行卷积,复杂度为 \(O(n^22^n)\)。
for(int i=0;i<=n;++i) FWT(f[i],1),FWT(g[i],1);
for(int i=0;i<=n;++i)
for(int j=0;j<=i;++j)
for(int s=0;s<all;++s)
h[i][s]=(h[i][s]+(ll)f[i-j][s]*g[j][s]%p)%p;
for(int i=0;i<=n;++i) FWT(h[i],-1);