「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}\)
\(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;
}