给定
考虑 FZT,即子集计数,具体可参考 FZT - 子集计数学习笔记 或 [ABC213G] Connectivity 2 Solution,发现本题与 ABC213G 相似。
因为本题存在选的边数的限制,所以不难想到需要在一般 FZT 的状态中额外添加一维记录。
状态类比 ABC213G,较为显然,令
首先考虑如何处理
然后发现这个东西有重复,不难想到重复分为两种,一种是因为
或:
然后初始值大概是
不难发现如果无脑处理
则预处理
然后矩阵树定理的结论大概就是首先对这个图建出拉普拉斯矩阵
于是考虑如何转移 __builtin_popcount(S),不难发现转移:
也就是钦定一个子集为一棵树,然后剩下的作为森林,钦定
不过很遗憾这个又是错的。我们在 ABC213G 中钦定
边界条件的话就是如果
然后考虑答案,令
也不难理解,概率转计数,总方案数为
大概就这样了,处理
xxxxxxxxxx105123
45678910
11using namespace std;12
13mt19937 rnd(random_device{}());14int rndd(int l, int r){return rnd() % (r - l + 1) + l;}15bool rnddd(int x){return rndd(1, 100) <= x;}16
17typedef unsigned int uint;18typedef unsigned long long unll;19typedef long long ll;20typedef long double ld;21
22232425
26template < typename T = int >27inline T read(void);28
29struct Edge{30 Edge* nxt;31 int to;32 OPNEW;33}ed[1100];34ROPNEW(ed);35Edge* head[20];36
37int N, M;38int deg[20];39ll G[MAX_STATUS], F[20][MAX_STATUS];40int cnte[MAX_STATUS];41ll fact[30];42
43int lowbit(int x){return x & -x;}44int CalCnt(int S, int T){return cnte[S | T] - cnte[S] - cnte[T];}45ll qpow(ll a, ll b){46 ll ret(1), mul(a);47 while(b){48 if(b & 1)ret = ret * mul % MOD;49 b >>= 1;50 mul = mul * mul % MOD;51 }return ret;52}53
54int main(){fact[0] = 1;55 for(int i = 1; i <= 20; ++i)fact[i] = fact[i - 1] * i % MOD;56 N = read(), M = read();57 const int Smx = (1 << N) - 1;58 for(int i = 1; i <= M; ++i){59 int s = read(), t = read();60 head[s] = new Edge{head[s], t};61 head[t] = new Edge{head[t], s};62 }63 for(int S = Smx; S; S = (S - 1) & Smx){64 int cnt(0);65 for(int p = 1; p <= N; ++p)66 for(auto i = head[p]; i; i = i->nxt)67 if(EXIST(p) && EXIST(SON))++cnt;68 cnt >>= 1;69 cnte[S] = cnt;70 }71 for(int S = 1; S <= Smx; ++S){72 if(__builtin_popcount(S) == 1){G[S] = 1; continue;}73 for(int T = (S - 1) & S; T; T = (T - 1) & S)74 if(T & lowbit(S))75 (G[S] += G[T] * G[S ^ T] % MOD * CalCnt(T, S ^ T) % MOD) %= MOD;76 (G[S] *= qpow(__builtin_popcount(S) - 1, MOD - 2)) %= MOD;77 }78 for(int i = 0; i <= N - 1; ++i)79 for(int S = 0; S <= Smx; ++S){80 if(__builtin_popcount(S) == i + 1){F[i][S] = G[S]; continue;}81 for(int T = (S - 1) & S; T; T = (T - 1) & S)82 if(T & lowbit(S) && i - (__builtin_popcount(T) - 1) >= 0)83 (F[i][S] += G[T] * F[i - (__builtin_popcount(T) - 1)][S ^ T]) %= MOD;84 }85 for(int i = 1; i <= N - 1; ++i)86 printf("%lld\n", F[i][Smx] * fact[i] % MOD * qpow(qpow(M, i), MOD - 2) % MOD);87 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);88 return 0;89}90
91template < typename T >92inline T read(void){93 T ret(0);94 int flag(1);95 char c = getchar();96 while(c != '-' && !isdigit(c))c = getchar();97 if(c == '-')flag = -1, c = getchar();98 while(isdigit(c)){99 ret *= 10;100 ret += int(c - '0');101 c = getchar();102 }103 ret *= flag;104 return ret;105}update-2022_12_07 初稿