【题目链接】
- 点击打开链接
【思路要点】
- 考虑给定的图为大小为 N + 1 N+1 N+1 的点的菊花图的情况,记方案数为 d p N dp_N dpN ,考虑最后一个儿子是否连边,则有转移 d p i = d p i − 1 + ( i − 1 ) d p i − 2 dp_i=dp_{i-1}+(i-1)dp_{i-2} dpi=dpi−1+(i−1)dpi−2
- 断开环边,剩余问题即为如何解决图是一棵树的情况。
- 注意到由于不允许存在重边,一个合法的加边方案中边的长度 ≥ 2 \geq2 ≥2 。
- 考虑对一个合法的加边方案进行如下转化:记一条边 ( x , y ) (x,y) (x,y) 经过了点 x , a , b , c , … , d , e , f , y x,a,b,c,\dots,d,e,f,y x,a,b,c,…,d,e,f,y ,则断开 ( x , y ) (x,y) (x,y) ,连接 ( x , b ) , ( a , c ) , … , ( d , f ) , ( e , y ) (x,b),(a,c),\dots,(d,f),(e,y) (x,b),(a,c),…,(d,f),(e,y) 。
- 得到的连边方案所连的新边长度均为 2 2 2 ,且与将各个点与其邻点看做一个菊花图的连边方案的组合一一对应。
- 因此,记 d i d_i di 为 i i i 的度数,答案即为 ∏ i = 1 N d p d i \prod_{i=1}^{N}dp_{d_i} i=1∏Ndpdi
- 时间复杂度 O ( N + M ) O(N+M) O(N+M) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 5e5 + 5; const int P = 998244353; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) {x = 0; int f = 1;char c = getchar();for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';x *= f; } template <typename T> void write(T x) {if (x < 0) x = -x, putchar('-');if (x > 9) write(x / 10);putchar(x % 10 + '0'); } template <typename T> void writeln(T x) {write(x);puts(""); } int n, m, cnt[MAXN], dp[MAXN]; bool vis[MAXN], ban[MAXN], ins[MAXN], flg; vector <pair <int, int>> a[MAXN]; void dfs(int pos, int fa, int num) {cnt[pos] = 0;vis[pos] = true;ins[pos] = true;for (auto x : a[pos])if (!vis[x.first]) {dfs(x.first, pos, x.second);cnt[pos] += cnt[x.first];} else if (ins[x.first] && x.first != fa) {cnt[pos]++, cnt[x.first]--;ban[x.second] = true;}ins[pos] = false;if (cnt[pos] >= 2) flg = true;if (cnt[pos] >= 1) ban[num] = true; } int main() {int T; read(T);while (T--) {read(n), read(m);for (int i = 1; i <= n; i++) {a[i].clear();vis[i] = false;}for (int i = 1; i <= m; i++) {int x, y; read(x), read(y);a[x].emplace_back(y, i);a[y].emplace_back(x, i);ban[i] = false;}flg = false;dfs(1, 0, 0);if (flg) {puts("0");continue;}dp[0] = dp[1] = 1;for (int i = 2; i <= n; i++)dp[i] = (dp[i - 1] + 1ll * (i - 1) * dp[i - 2]) % P;int ans = 1;for (int i = 1; i <= n; i++) {int cnt = 0;for (auto x : a[i])if (!ban[x.second]) cnt++;ans = 1ll * ans * dp[cnt] % P;}writeln(ans);}return 0; }