zoukankan      html  css  js  c++  java
  • [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;
    }
    
  • 相关阅读:
    PHP基础1
    U2-Net网络学习笔记(记录)
    C++贪吃蛇游戏
    实习期间学习基础学习整理
    week 2020.1.10-2020.1.15
    week 2021.1.04-2021.1.08
    week 2020.12.21-2020.12.31
    周记 week 2020-12.14-12.18
    几种读取图片和标签的方法
    图像风格转换(Style Transfer | 风格迁移综述)
  • 原文地址:https://www.cnblogs.com/ac-evil/p/14750628.html
Copyright © 2011-2022 走看看