P4921 [MtOI2018] 情侣关系,为何要被烧毁呢?

摘要:P4921 [MtOI2018] 情侣?给我烧了! 大意 (n) 对情侣,恰好 (k) 对在 (2 times n) 的电影院中坐一起的方案数。 思路 很好的题目,使得我的大脑旋转。 首先我们先定义函数 (f(n, k))
P4921 [MtOI2018] 情侣?给我烧了! 大意 \(n\) 对情侣,恰好 \(k\) 对在 \(2 \times n\) 的电影院中坐一起的方案数。 思路 很好的题目,使得我的大脑旋转。 首先我们先定义函数 \(f(n, k)\) 表示 \(n\) 对情侣有 \(k\) 对恰好坐到一块的方案数。首先我们要从 \(n\) 对情侣中选择 \(k\) 对,这个是 \(\binom{n}{k}\) 的,再从 \(n\) 排选择 \(k\) 排,这个也是 \(\binom{n}{k}\) 的,考虑到这 \(k\) 对情侣间也有先后顺序,贡献就是 \(k!\),两人可以换位,贡献是 \(2 ^ k\),剩下有 \(n - k\) 对情侣,我们只需要将其错排即可。 定义 \(g(m)\) 表示 \(m\) 对情侣错排的方案数,我们考虑这个怎么求。这个我们可以利用容斥原理,我们考虑直接计算至少 \(j\) 对和睦的方案数,那么这个的贡献与上面的类似,应当是 \(\binom{m}{j} ^ 2 j! 2 ^ j (2(m - j))!\),那么由容斥可知: \[g(m) = \sum_{j = 0} ^ {m}(-1) ^ j \binom{m}{j} ^ 2 j! 2 ^ j (2(m - j))! \] 那么我们合并一下整个式子,就是: \[f(n, k) = \binom{n}{k} ^ 2 k ! 2 ^ k g(n - k) \\ = \binom{n}{k} ^ 2 k ! 2 ^ k \sum_{j = 0} ^ {n - k}(-1) ^ j \binom{n - k}{j} ^ 2 j! 2 ^ j (2(n - k - j))! \] 这个式子我们是可以直接求的,于是就完成了。 代码 #include<iostream> using namespace std; #define int long long const int MOD = 998244353; const int MAXN = 2e3 + 5; int C[MAXN][MAXN]; int fac[MAXN]; int g[MAXN], pow2[MAXN]; void init(){ C[0][0] = 1; for(int i = 1;i < MAXN;i ++){ C[i][0] = C[i][i] = 1; for(int j = 1;j < i;j ++){ C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD; } } fac[0] = 1; for(int i = 1;i < MAXN;i ++){ fac[i] = (fac[i - 1] * i) % MOD; } pow2[0] = 1; for(int i = 1;i < MAXN;i ++){ pow2[i] = pow2[i - 1] * 2 % MOD; } for(int m = 0;m <= 1000;m ++){ g[m] = 0; for(int j = 0;j <= m;j ++){ int a = (j % 2 == 0) ? 1 : MOD - 1; int res = C[m][j] * C[m][j] % MOD; res = (res * fac[j]) % MOD; res = (res * pow2[j]) % MOD; res = (res * fac[2 * (m - j)]) % MOD; res = (res * a) % MOD; g[m] = (g[m] + res) % MOD; } } return; } int f(int n, int k){ int res = (C[n][k] * C[n][k]) % MOD; res = (res * fac[k]) % MOD; res = (res * pow2[k]) % MOD; res = (res * g[n - k]) % MOD; return res; } int T, n, k; signed main(){ ios::sync_with_stdio(0); cin.tie(0); init(); cin >> T; while(T --){ cin >> n; for(int i = 0;i <= n;i ++){ cout << f(n, i) << '\n'; } } return 0; }