P4931 [MtOI2018] 情侣关系是否应该被打破?

摘要:P4931 [MtOI2018] 情侣?给我烧了!(加强版) 大意 (n) 对情侣,恰好 (k) 对在 (2 times n) 的电影院中坐一起的方案数。 思路 弱化版的可以去看 P4921 [MtOI2018] 情侣?给我烧
P4931 [MtOI2018] 情侣?给我烧了!(加强版) 大意 \(n\) 对情侣,恰好 \(k\) 对在 \(2 \times n\) 的电影院中坐一起的方案数。 思路 弱化版的可以去看 P4921 [MtOI2018] 情侣?给我烧了! 接下来进入正题,我们注意到刚刚的弱化版内的 $f(n, k) = \binom{n}{k} ^ 2 k ! 2 ^ k D(n - k) $,且 \(D(n) = \sum_{i = 0} ^ {n} (-1) ^ i\binom{n}{i} ^ 2 i! 2 ^ i (2(n - i))!\),我们考虑对于 \(g(n)\) 进行化简. \[\sum_{i = 0} ^ {n}(-1) \binom{n}{i} ^ 2 i! 2 ^ i (2(n - i)) ! \\ = (n!) ^ 2 \sum_{i = 0} ^ n \frac{(2(n - i))!}{(n - i)! ^ 2} \frac{(-2) ^ i}{i!} \] 这里我们就可以直接做卷积了,但是问题在于这个题目要求的复杂度太过苛刻,卷积无法通过此题,我们考虑构造生成函数。 我们设: \[F(x) = (n!) ^ 2 \sum_{i = 0} ^ n \frac{(2(n - i))!}{(n - i)! ^ 2} \frac{(-2) ^ i}{i!} x^i \\ G[n] = \frac{(2n)!}{n!^2},P[n] = \frac{(-2) ^ i}{n !} \] 那么,由离散卷积可知: \[F(x) = G(x) * P(x) \] 接下来,我们只需要分别对于 \(G(x)\) 和 \(P(x)\) 化简即可。 首先,对于 \(G(x)\) 来说,我们可以利用广义二项式定理,那么什么是广义二项式定理呢?对于任意实数 \(\alpha\),都有 \((1 + z) ^ \alpha = \sum_{i = 0} ^ {\infty} \binom{\alpha}{i} z ^ i\),那么说我们就可以化简 \(G(x)\) 了: \[G(x) = \sum_{i = 0} \frac{(-2x) ^ i}{i!} x ^ i = \sum_{i = 0} \binom{2i}{i}x^i = \frac{1}{\sqrt{1 - 4x}} \] 对于 \(P(x)\) 来说,直接化简: \[P(x) = \sum_{i = 0} \frac{(-2x)!}{i!} = e ^ {-2x} \] 经过化简,我们可以最终得到: \[F(x) = \frac{e ^ {-2x}}{\sqrt{1 - 4x}} \] 对于这个生成函数,为了得到与自身相关的式子进行递推,我们选择对其求导。 \[F'(x) = \frac{8x * e ^ {-2x}}{(1 - 4x) ^ \frac{3}{2}} = \frac{8x}{1 - 4x} F(x) \] 整理一下: \[F'(x) = 4xF'(x) + 8xF(x) \] 提取 \([x ^ n]\) 的系数: \[F'[n] = 4xF'[n - 1] + 8xF[n - 1] \] 稍施小计,我们可以直接得到关于 \(F[n]\) 的递推式: \[(n + 1)F[n + 1] = 4nF[n] + 8F[n - 1] \] 你可能以为万事大吉了,但是问题是我们还有个 \((n!) ^ 2\) 的系数在最开始被我们提出去了,我们要把这玩意弄回来,带入 \(F[n] = \frac{D(n)}{n!} ^ 2\): \[(n + 1)\frac{D[n + 1]}{(n + 1)!} = 4n \frac{D[n]}{n!^2} + 8 \frac{D[n - 1]}{(n - 1)! ^ 2} \] 我们就可以得到关于 \(D[n]\) 的递推式: \[D[n + 1] = 4n(n + 1)D[n] + 8n ^ 2(n + 1)D[n - 1] \] 直接 \(O(n)\) 递推即可。 代码 #include<iostream> using namespace std; #define int long long const int MOD = 998244353; const int MXN = 5000005; int fac[MXN], inv[MXN], pow2[MXN], g[MXN]; int pw(int x, int y){ int res = 1; x %= MOD; while(y){ if(y & 1) res = (res * x) % MOD; x = (x * x) % MOD; y >>= 1; } return res; } void init(){ fac[0] = pow2[0] = 1; for(int i = 1;i < MXN;i ++){ fac[i] = (fac[i - 1] * i) % MOD; pow2[i] = (pow2[i - 1] * 2) % MOD; } inv[MXN - 1] = pw(fac[MXN - 1], MOD - 2); for(int i = MXN - 2;i >= 0;i --) inv[i] = (inv[i + 1] * (i + 1)) % MOD; g[0] = 1; g[1] = 0; for(int i = 2;i < MXN;i ++){ int A = (4 * i % MOD * (i - 1)) % MOD; int B = (g[i - 1] + (2 * i - 2) * g[i - 2]) % MOD; g[i] = (A * B) % MOD; } } int C(int n, int k){ if(k < 0 || k > n) return 0; return fac[n] * inv[k] % MOD * inv[n - k] % MOD; } 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; } signed main(){ ios::sync_with_stdio(0); cin.tie(0); init(); int T, n, k; cin >> T; while(T --){ cin >> n >> k; cout << f(n, k) << '\n'; } return 0; }