【题解】#6622. 「THUPC 2019」找树 / findtree(Matrix Tree+FWT)
之前做这道题不理解,有一点走火入魔了,甚至想要一本近世代数来看,然后通过人类智慧思考后发现,这道理可以用打马后炮别的方式来理解。
先放松一点条件,假如位运算只有一种,定位某一颗生成树,那么可以知道
\[ w(T)=\oplus_{w\in W} w \]
写成生成函数的形式,对于每条边就是
\[ h((i,j))=[\exist e=(i,j,w)]x^w \]
现在重边可以看做一条边了
那么可以知道
\[ h(T)=\oplus h(w|w\in W) \]
很显然,我们对\(h(x)\)做FWT,就得到了\(H(x)\)
\[ H(T)=* H(w) \]
其中\(*\)表示点积。
考虑这个FWT函数的每一位,它都是由点积而来的,也就是说第x位上H(T)数组的最终值和其他位置上的值无关。
那么我们对每条边做一个FWT后,每两个点之间有一个\(2^w\)次方大小的数组(w是题目里的w),对于每一个值都做一遍Matrix Tree,得到了一个值\(c_w\)。
根据Matrix Tree的原理,这就相当于\(O({m\choose n-1})\)地枚举边集,然后再将每条边的边权(一个生成函数做沃氏变换后变成的生成函数)相乘求和。显然就有了\(H=C\)。
还有一个问题是题目给定的鬼畜的运算,有个东西叫做扩展FWT,具体做法是对于每一位判断一下是哪个运算,然后直接按照对应的运算法则算就行。正确性可能显然?
于是这道题就完成了
//@winlere
#include
#include
#include
#include
#include
#include
using namespace std; typedef long long ll;
inline int qr(){
int ret=0,f=0,c=getchar();
while(!isdigit(c))f|=c==45,c=getchar();
while(isdigit(c)) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int mod=998244353;
const int gi=(mod+1)/3;
const int g=3;
const int inv2=(mod+1)>>1;
const int maxn=13;
int n,m,ty[1< poly;
poly Mat[75][75],a[71];
inline int MOD(const int&x){return x>=mod?x-mod:x;}
inline int MOD(const int&x,const int&y){return 1ll*x*y%mod;}
inline int ksm(const int&ba,const int&p){
int ret=1;
for(int t=p,b=ba%mod;t;t>>=1,b=MOD(b,b))
if(t&1) ret=MOD(ret,b);
return ret;
}
inline int inv(int x){return ksm(x,mod-2);}
void FWT(poly&a,int op){
int len=a.size();
for(int t=1,c=0;t