给定
考虑 FZT,即子集计数,具体可参考 FZT - 子集计数学习笔记 或 [ABC213G] Connectivity 2 Solution,发现本题与 ABC213G 相似。
因为本题存在选的边数的限制,所以不难想到需要在一般 FZT 的状态中额外添加一维记录。
状态类比 ABC213G,较为显然,令
首先考虑如何处理
然后发现这个东西有重复,不难想到重复分为两种,一种是因为
或:
然后初始值大概是
不难发现如果无脑处理
则预处理
然后矩阵树定理的结论大概就是首先对这个图建出拉普拉斯矩阵
于是考虑如何转移 __builtin_popcount(S)
,不难发现转移:
也就是钦定一个子集为一棵树,然后剩下的作为森林,钦定
不过很遗憾这个又是错的。我们在 ABC213G 中钦定
边界条件的话就是如果
然后考虑答案,令
也不难理解,概率转计数,总方案数为
大概就这样了,处理
xxxxxxxxxx
1051
2
3
4
5
6
7
8
9
10
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
22
23
24
25
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 初稿