集合冪級數的ln和exp運算及組合意義
子集卷積
設\(f,g,h\)為集合冪級數
定義\(h\)為\(f\)和\(g\)的子集卷積
注意到\([L \cap R=\emptyset][L \cup R=S]=[|L|+|R|=|S|][L \cup R=S]\)
我們定義集合占位冪級數 \(F_{i,S}\),\(F_{|S|,S}=f_S\),其余情況為0
那么上面的式子就可以簡化為
容易發現,第一維是一個普通卷積,而第二維是集合冪級數的or卷積. 而集合占位冪級數可以看成一個二元生成函數,每一維之間是獨立的,只需要分開即可.(可以考慮多項式的乘法如\((xy+x^2y)(2x^2y+3y^2)\),感性理解即可)
那么我們處理這個卷積時,只需要對每一行\(f_i\)做FMT,然后對於每一列,暴力做普通卷積,再把每一行IFMT回來即可。因為有\(n\)行\(2^n\)列,所以復雜度\(O(n^22^n)\)
集合冪級數exp
我們考慮EGF的組合意義,EGF的exp表示把元素組合成集合的方案數。不妨定義\(F_{|S|,S}=\frac{f_S}{|S|!}\). 那么每一列就是一個EGF. 我們先定義占位集合冪級數的exp為\(\exp F -1=\sum_{i\geq 1}\frac{F^i}{i!}\),其中\(F\)的乘法定義為子集卷積. 由於占位集合冪級數中中兩維的獨立性,這等價於對第一維做普通卷積意義下的exp,對第二維做or卷積.
實現時,類似子集卷積,先對行FMT,再列exp,再IFMT回來即可. 對列做exp,當然可以用多項式全家桶做到\(O(n\log n)\),但常數爆炸。因為\(n\)很小,考慮如何\(O(n^2)\)做exp.
設\(G=\exp F -1\)
兩邊求導得\(G'=F' \exp F=F'G\)
寫成系數形式\(ng_n=\sum_{i=0}^{n-1}if_ig_{n-i}\),即
集合冪級數的exp好像十分抽象,我們現在探討它的組合意義. 設\(g_n\)為真實的方案數(沒有除掉EGF中的n!)
組合解釋如下: 枚舉\(n\)所在的集合的大小\(i\),那么該集合內部的方案數為\(f_i\).從的\(n-1\)個數中選\(i-1\)個數與\(n\)放到同一集合。剩下的\(n-i\)個數隨便放,方案數\(g_{n-i}\). 那么exp的意義就是選取若干個不相交的集合組合成S的方案數。
void exp(int *f,int *g,int n){
static int F[maxlogn+5][maxn+5],G[maxlogn+5][maxn+5];
for(int i=0;i<(1<<n);i++) for(int j=0;j<=n;j++) F[j][i]=G[j][i]=0;
for(int i=0;i<(1<<n);i++) F[cnt[i]][i]=f[i];
for(int i=0;i<=n;i++) FMT(F[i],n,1);
G[0][0]=1;
FMT(G[0],n,1);
for(int s=0;s<(1<<n);s++){
for(int i=1;i<=n;i++){
for(int j=0;j<=i-1;j++) G[i][s]=addm(G[i][s],1ll*F[j][s]*j*G[i-j][s]%mod);
G[i][s]=1ll*G[i][s]*invi[i]%mod;
}
}
for(int i=0;i<=n;i++) FMT(G[i],n,-1);
for(int i=0;i<(1<<n);i++) g[i]=G[cnt[i]][i];
}
定義\(G\)的生成子圖為包含\(G\)的所有頂點的子圖。給出一個圖G,求G的連通生成子圖數量
集合冪級數ln
之前我們定義了\(e^G-1=F\).同理,我們定義\(G=\ln(F+1)\)
同樣,對第一維做普通卷積意義下的ln,對第二維做or卷積.考慮如何\(O(n^2)\)ln.
我們只需要把exp的式子反過來就好了
再把字母換一下就得到了
由exp的組合意義可知,ln的組合意義為將S拆分成若干個不相交集合的方案數
void ln(int *f,int *g,int n){
static int F[maxlogn+5][maxn+5],G[maxlogn+5][maxn+5];
for(int i=0;i<(1<<n);i++) for(int j=0;j<=n;j++) F[j][i]=G[j][i]=0;
for(int i=0;i<(1<<n);i++) F[cnt[i]][i]=f[i];
for(int i=0;i<=n;i++) FMT(F[i],n,1);
G[0][0]=1;
FMT(G[0],n,1);
for(int s=0;s<(1<<n);s++){
for(int i=1;i<=n;i++){
for(int j=0;j<=i-1;j++) G[i][s]=addm(G[i][s],1ll*F[i-j][s]*G[j][s]%mod*j%mod);
G[i][s]=decm(F[i][s],1ll*G[i][s]*invi[i]%mod)%mod;
}
}
for(int i=0;i<=n;i++) FMT(G[i],n,-1);
for(int i=0;i<(1<<n);i++) g[i]=G[cnt[i]][i];
}
k-exp
我們在ln和exp的定義中,都沒有限制拆分成集合的個數,如\(\sum_{i \geq 1}\frac{F^i}{i!}\),i的取值是1到n. 如果限制拆分的個數之多為k,我們就得到了k-exp
即\(G=\sum_{i=1}^k \frac{F^i}{i!}\)
同樣兩邊求導,有\(G'=F'(G-\frac{F^k}{k!})\),因為對右邊求導后,每一項都變成了前一項,只有第k項消失了
同樣考慮每一列怎么做.對\(F^k\)做多項式快速冪(即先ln,乘k再exp),設得到的結果為\(h\).那么上式就可以寫成
\(ng_n=\sum_{i=0}^{n-1}(n-i)f_{n-i}(g_i-h_i)\)
就可以在\(O(n^2)\)的時間內求解