[CTS2019] 珍珠

Problem

(n) 个范围在 ([1,D]) 内的整数均匀随机变量,求至少能选出 (m) 个瓶子,使得存在一种方案,选择一些变量,并把选出来的每一个变量放到一个瓶子中,满足每个瓶子都恰好装两个值相同的变量的概率。答案乘上 (D^n)(998244353) 取模。

(Dle 10^5)(n,mle 10^9)

Sol

首先根据奇偶性,写出来关于每种颜色的多项式((x) 表示选出来的数目,(y) 表示能组合的 pair ( imes 2)

[F(x,y)=frac{e^{xy}+e^{-xy}}2+frac{e^{xy}-e^{-xy}}{2y} ]

答案为

[Ans=n![x^ny^{ge2m}]F^D(x,y) ]

[Rightarrow n![x^ny^{ge2m-n}]left(frac{e^x+e^{-x}}2+frac{e^x-e^{-x}}{2y} ight)^D ]

[Rightarrow n![x^ny^{ge 2m-n+D}]left(frac{e^x+e^{-x}}2y+frac{e^x-e^{-x}}2 ight)^D ]

无必要的 (y) 消掉了。

展开右式

[sum_{i=0}^D{Dchoose i}y^ileft(frac{e^x+e^{-x}}2 ight)^ileft(frac{e^x-e^{-x}}2 ight)^{D-i} ]

答案变成

[Ans=n![x^n]sum_{i=a}^D{Dchoose i}left(frac{e^x+e^{-x}}2 ight)^ileft(frac{e^x-e^{-x}}2 ight)^{D-i} ]

这里 (a=2m-n+D)

继续考察右式

[egin{aligned} &sum_{i=a}^D{Dchoose i}left(frac{e^x+e^{-x}}2 ight)^ileft(frac{e^x-e^{-x}}2 ight)^{D-i}\ =&2^{-D}e^{-Dx}sum_{i=a}^D{Dchoose i}(e^{2x}+1)^i(e^{2x}-1)^{D-i} end{aligned} ]

这里重点来看后半部分。暂时用 (x) 替换 (e^{2x})

[egin{aligned} sum_{i=a}^D{Dchoose i}(x+1)^i(x-1)^{D-i} end{aligned} ]

它一定可以变成

[sum_{i=0}^Da_ix^i ]

这样子就可以解决问题了,现在我们来尝试化简。这里令 (z=x+1),则式子变成

[egin{aligned} &sum_{i=a}^D{Dchoose i}z^i(z-2)^{D-i}\ =&sum_{i=a}^D{Dchoose i}sum_{j=0}^{D-i}{D-ichoose j}(-2)^{D-i-j}z^{i+j}\ =&sum_{i=a}^D(-2)^{D-i}z^isum_{j=0}^{i-a}{Dchoose i-j}{D-(i-j)choose j}\ =&sum_{i=a}^D(-2)^{D-i}z^i{Dchoose i}sum_{j=0}^{i-a}{ichoose j} end{aligned} ]

发现 (sum_{j=0}^{i-a}{ichoose j}) 是可以递推的!于是我们可以在 (mathcal O(D)) 的时间求出上面的多项式,对 (z) 做平移得到原来的多项式,问题得解。最后得到

[Ans=n![x^n]sum_{i=0}^Df_ie^{(2i-D)x} ]

直接解系数即可。复杂度 (mathcal O(Dlog n))

附平移多项式推导

[egin{aligned} f(x+c)&=sum_{i=0}^na_i(x+c)^i\ &=sum_{i=0}^na_isum_{j=0}^i{ichoose j}x^jc^{i-j}\ &=sum_{j=0}^nfrac{x^j}{j!}sum_{i=j}^ni!a_ifrac{c^{i-j}}{(i-j)!} end{aligned} ]

NTT 即可。

Code

#include <bits/stdc++.h>
using std::max;
const int N = 100005, P = 998244353;
int D, n, m, a[N * 4], b[N * 4], s;
int inc(int a, int b) { return (a += b) >= P ? a - P : a; }
int qpow(int a, int b) {
	int t = 1;
	for (; b; b >>= 1, a = 1LL * a * a % P)
		if (b & 1) t = 1LL * t * a % P;
	return t;
}
int W[N * 4], inv[N], fac[N], ifac[N];
int C(int n, int m) {
	if (n < 0 || m > n) return 0;
	return 1LL * fac[n] * ifac[m] % P * ifac[n - m] % P;
}
void prework(int n) {
	for (int i = 1; i < n; i <<= 1)
		for (int j = W[i] = 1, Wn = qpow(3, (P - 1) / i >> 1); j < n; j++)
			W[i + j] = 1LL * W[i + j - 1] * Wn % P;
}
void fft(int *a, int n, int op) {
	static int rev[N * 4] = {0};
	for (int i = 0; i < n; i++)
		if ((rev[i] = rev[i >> 1] >> 1 | (i & 1 ? n >> 1 : 0)) > i) std::swap(a[i], a[rev[i]]);
	for (int q = 1; q < n; q <<= 1)
		for (int p = 0; p < n; p += q << 1)
			for (int i = 0, t; i < q; i++)
				t = 1LL * W[q+i] * a[p+q+i] % P, a[p+q+i] = inc(a[p+i], P-t), a[p+i] = inc(a[p+i], t);
	if (op) return;
	for (int i = 0, inv = qpow(n, P - 2); i < n; i++)
		a[i] = 1LL * a[i] * inv % P;
	std::reverse(a + 1, a + n);
}
int getsz(int n) { int x = 1; while (x < n) x <<= 1; return x; }
int main() {
	scanf("%d%d%d", &D, &n, &m);
	prework((D + 1) * 2);
	inv[1] = fac[0] = ifac[0] = 1;
	for (int i = 2; i <= D; i++)
		inv[i] = 1LL * (P - P / i) * inv[P % i] % P;
	for (int i = 1; i <= D; i++)
		fac[i] = 1LL * fac[i - 1] * i % P, ifac[i] = 1LL * ifac[i - 1] * inv[i] % P;
	s = 2 * m - n + D;
	int tmp = 1;
	for (int i = max(0, s); i <= D; i++) {
		a[i] = 1LL * qpow(P - 2, D - i) * C(D, i) % P * tmp % P * fac[i] % P;
		tmp = (2LL * tmp + C(i, i - s + 1)) % P;
	}
	for (int i = 0; i <= D; i++)
		b[i] = ifac[i];
	std::reverse(b, b + D + 1);
	int l = getsz(2 * (D + 1));
	fft(a, l, 1), fft(b, l, 1);
	for (int i = 0; i < l; i++) a[i] = 1LL * a[i] * b[i] % P;
	fft(a, l, 0);
	int ans = 0;
	for (int i = 0; i <= D; i++) {
		a[i + D] = 1LL * a[i + D] * ifac[i] % P;
		ans = (ans + 1LL * a[i + D] * qpow((2 * i - D + P) % P, n)) % P;
	}
	ans = 1LL * ans * qpow((P + 1) / 2, D) % P;
	printf("%d
", ans);
	return 0;
}
原文地址:https://www.cnblogs.com/ac-evil/p/14750628.html