「CTS2019 | CTSC2019」珍珠

「CTS2019 | CTSC2019」珍珠

题目描述:

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

思路

答案只与最终奇数的个数有关,偶数个都是可以直接匹配的。设剩下\(t\)个奇数,那么能匹配出的数量就是\((n-t)/2\) 如果\((n-D)/2>=m\)那就是可以随便放,\(n/2<m\)说明无解。

1-12

\(dp[i][j]\) 表示取到了第\(i\)个数,此时没有配对的个数为\(j\)的概率,那么能配对的个数就是\((n-j)/2\)

就是方案数

12-15

构造生成函数。

因为最终的结果只和奇数的个数有关,假设\(G_i\)表示恰好有\(i\)个奇数,对于恰好的问题可以考虑改成容斥,所以用\(f_k\)表示至少有\(k\)个奇数的方案数。

前置知识:

泰勒展开:\(e^x=\sum_{i=0}^{∞}\frac{x^i}{i!}\) (可以当做是随便取)

关于奇数的指数型函数:\(\frac{e^x-e^{-x}}{2}=\sum_{i=0}^{∞}\frac{x^{2i+1}}{(2i+1)!}\) (放进去表示只去奇数)

\(f_k\)表示至少有\(k\)个奇数

\(f_k=\binom{D}{k}[x^n]*n!*(\frac{e^x-e^{-x}}{2})^k*(e^x)^{D-k}\)

扫描二维码关注公众号,回复: 11244929 查看本文章

\(f_k=\binom{D}{k}[x^n]*\frac{n!}{2^k}*(e^x-e^{-x})^k*(e^x)^{D-k}\)

\((e^x-e^{-x})^k\)二项式展开和后面的进行合并

\(f_k=\binom{D}{k}\frac{n!}{2^k}*\sum_{j=0}^{k}\binom{k}{j}(-1)^{k-j}*e^{(D-2*(k-j))x}[x^n]\)

\(e^{ax}=\sum_{i=0}^{∞}\frac{(ax)^i}{i!}=\frac{a^ix^i}{i!}\)

所以第\(n\)位的系数就是\(\frac{a^i}{i!}\)

\(f_k=\binom{D}{k}\frac{n!}{2^k}*\sum_{j=0}^{k}\binom{k}{j}(-1)^{k-j}*\frac{(D-2*(k-j))^n}{n!}\)

\(f_k=\frac{D!}{(D-k)!*2^k}\sum_{j=0}^{k}\frac{(-1)^{k-j}}{(k-j)!*(j!)}*(D-2k-2j)^n\)

\(k-j=j\)(即改成枚举k-j) 就变成了

\(f_k=\frac{D!}{(D-k)!*2^k}\sum_{j=0}^{k}\frac{(-1)^j}{(k-j)!*(j!)}*(D-2j)^n\)

\(f_k=\frac{D!}{(D-k)!*2^k}\sum_{j=0}^{k}\frac{(-1)^j*(D-2j)^n}{(j!)}*\frac{1}{(k-j)!}\)

然后后半部分可以进行卷积

\(g=\sum_{j=0}^{k}\frac{(-1)^j*(D-2j)^n}{(j!)}\)

\(t=\sum_{j=0}^{k}\frac{1}{j!}\)

\(p=g*t\)

\(f_k=\frac{D!}{(D-k)!*2^k}*p(k)\)

设恰好有\(k\)个奇数为G

\(G_i=\sum_{j}\binom{j}{i}*(-1)^{j-i}*f_j\)

\(G_i=\frac{1}{i!}\sum_j j!*f_j*\frac{(-1)^{j-i}}{(j-i)!}\)

然后再进行一次卷积

右边要变成\(i-j\)的形式,-(i-j)是正数

\(G_i=\frac{1}{i!}\sum_jj!*f_j*\frac{(-1)^{i-j}}{[-(i-j)]!}\)

#include<bits/stdc++.h>
#define ll long long
#define M 100005
using namespace std;
const int Mod=998244353,w0=3,w1=332748118;
void Rd(int &res) {
	res=0;
	char c;
	int fl=1;
	while(c=getchar(),c<48)if(c=='-')fl=-1;
	do res=(res<<1)+(res<<3)+(c^48);
	while(c=getchar(),c>=48);
	res*=fl;
}
int D,n,m,R[M<<2];
void add(ll &x,ll y) {
	x+=y;
	if(x>=Mod)x-=Mod;
	if(x<0)x+=Mod;
}
ll mul(ll x,ll y) {
	ll res=1;
	x=(x%Mod+Mod)%Mod;
	while(y) {
		if(y&1)res=res*x%Mod;
		x=x*x%Mod,y>>=1;
	}
	return res;
}
void NTT(ll *a,int n,int op) {
	for(int i=0; i<n; i++)if(i<R[i])swap(a[i],a[R[i]]);
	for(int i=2; i<=n; i<<=1) {
		int w=op?w1:w0;
		w=mul(w,((Mod-1)/i));//就是原根的n次方
		for(int j=0; j<n; j+=i) {
			int l=i/2,res=1;
			for(int k=0; k<l; k++) {
				int t=1ll*res*a[j+k+l]%Mod;
				a[j+k+l]=(a[j+k]-t+Mod)%Mod,a[j+k]=(a[j+k]+t)%Mod;
				res=1ll*res*w%Mod;
			}
		}
	}
	if(op) {
		ll res=mul(n,Mod-2);
		for(int i=0; i<n; i++)a[i]=a[i]*res%Mod;
	}
}
ll G[M<<2],T[M<<2],P[M<<2],pr[M],inv[M],F[M<<2];
int main() {
	Rd(D),Rd(n),Rd(m);
	if((n-D)>=2ll*m)printf("%lld\n",mul(D,n));
	else if(n<2ll*m)puts("0");
	else {
		pr[0]=inv[0]=1;
		for(int i=1; i<=D; i++)pr[i]=pr[i-1]*i%Mod;
		inv[D]=mul(pr[D],Mod-2);
		for(int i=D; i; i--)inv[i-1]=inv[i]*i%Mod;
		int res=1,l=0;
		for(int i=0; i<=D; i++)G[i]=res*mul(D-2*i,n)%Mod*inv[i]%Mod,res*=-1,G[i]=(G[i]+Mod)%Mod;
		for(int i=0; i<=D; i++)T[i]=inv[i];
		l=1,res=0;
		while(l<=D+D)l<<=1,res++;
		for(int i=D+1; i<l; i++)G[i]=T[i]=0;
		for(int i=0; i<l; i++)R[i]=(R[i>>1]>>1)|((i&1)<<(res-1));
		NTT(G,l,0),NTT(T,l,0);
		for(int i=0; i<l; i++)G[i]=G[i]*T[i]%Mod;
		NTT(G,l,1);
		res=1;
		for(int i=0; i<=D; i++)F[i]=pr[D]*inv[D-i]%Mod*res%Mod*G[i]%Mod,res=inv[2]*res%Mod;
		for(int i=D+1; i<l; i++)F[i]=T[i]=0;
		res=1;
		for(int i=0; i<=D; i++)F[i]=F[i]*pr[i]%Mod;
		for(int i=0; i<=D; i++)T[D-i]=res*inv[i]%Mod,add(T[D-i],Mod),res*=-1;
		NTT(F,l,0),NTT(T,l,0);
		for(int i=0; i<l; i++)F[i]=F[i]*T[i]%Mod;
		NTT(F,l,1);
		ll ans=0;
		for(int i=0; i<=D; i++)if((n-i)/2>=m)add(ans,F[D+i]*inv[i]%Mod);
		printf("%lld\n",ans);
	}
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/cly1231/p/12935687.html
今日推荐