Graph 題解
阿新 • • 發佈:2021-07-10
一、題目:
二、思路:
經典的圖計數問題。在這裡說明一下,由於筆者不會多項式全家桶,所以程式碼的時間複雜度是 \(O(n^2)\) 的。
首先設 \(g_i\) 表示區分左部和右部、圖不一定連通、含有 \(i\) 個點的方案數。則有 \(g_i=\sum\limits_{j=0}^i\dbinom{i}{j}3^{j(i-j)}\)。
注意,\(\dfrac{g_n}{2}\) 不是最終的答案!細想一下,$g_n $ 表示將 \(n\) 個點分入可區分的兩個集合,那麼 \(g_n/2\) 表示將 \(n\) 個點分入不可區分的兩個集合。比如說 \(\dfrac{g_2}{2}=4\),分別代表了這四種情況:
但是我們發現情況 1 和情況 2 代表了相同的圖。
設 \(f_i\) 表示不區分左部和右部、保證圖是連通的、包含 \(i\) 個點的方案數。則有
\[f_i=\dfrac{g_i}{2}-\sum\limits_{j=1}^{i-1}\dbinom{i-1}{j-1}\times f_j\times g_{i-j} \]用總方案數減去不連通的方案數。如何算出不連通的方案數呢?考慮列舉 1 號點所在連通塊的大小 \(j\)。我們發現,“不區分左部和右部”\(\Leftrightarrow\)“規定 1 號點所在‘部’為左部”。所以剩下的 \(i-j\) 個點仍要區分左右部。
最後設 \(h_i\)
三、程式碼;
// 64分的程式碼 #include <iostream> #include <cstdio> #include <ctime> #include <cstring> using namespace std; #define FILEIN(s) freopen(s, "r", stdin) #define FILEOUT(s) freopen(s, "w", stdout) #define mem(s, v) memset(s, v, sizeof s) inline int read(void) { int x = 0, f = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return f * x; } const int MOD = 998244353, MAXN = 7000; int factor[MAXN], facinv[MAXN], div2; int g[MAXN], f[MAXN], h[MAXN], N; inline int power(int a, int b) { int res = 1; for (; b; b >>= 1) { if (b & 1) res = 1LL * res * a % MOD; a = 1LL * a * a % MOD; } return res; } inline int C(int n, int m) { return 1LL * factor[n] * facinv[m] % MOD * facinv[n - m] % MOD; } inline void Add(int &a, int b) { a += b; if (a >= MOD) a -= MOD; } void prework(void) { factor[0] = 1; for (int i = 1; i <= N; ++ i) factor[i] = 1LL * factor[i - 1] * i % MOD, facinv[N] = power(factor[N], MOD - 2); for (int i = N - 1; i >= 0; -- i) facinv[i] = 1LL * facinv[i + 1] * (i + 1) % MOD; div2 = facinv[2]; h[0] = 1; for (int i = 1; i <= N; ++ i) { g[i] = 2; for (int j = 1; j <= i - 1; ++ j) { Add(g[i], 1LL * C(i, j) * power(3, j * (i - j)) % MOD); Add(f[i], 1LL * f[j] * g[i - j] % MOD * C(i - 1, j - 1) % MOD); Add(h[i], 1LL * f[j] * C(i - 1, j - 1) % MOD * h[i - j] % MOD); } f[i] = (1LL * g[i] * div2 % MOD - f[i] + MOD) % MOD; Add(h[i], f[i]); } } int main() { FILEIN("graph.in"); FILEOUT("graph.out"); N = read(); prework(); while (N --) printf("%d\n", h[read()]); return 0; }