[CTSC2019]珍珠 题解
[CTSC2019]珍珠 题解
Problem
有\(n\)个在范围\([1,D]\)内的整数均匀随机变量
求至少能选出\(m\)个瓶子,使得存在一种方案,选择一些变量,并把选出来的每一个变量放到一个瓶子中,满足每个瓶子都恰好装两个值相同的变量的概率
请输出概率乘上\(D^n\)后对998244353取模的值
Solution
考虑到\(n\)的范围是\(10^9\),我们可以换一个方向枚举,考虑枚举每个权值出现的次数,设其为\(A_i\)
那么,题目的要求就是:
\[\sum\limits_{i=1}^D \lfloor \frac{A_i}{2} \rfloor \ge m
\]
即:
\[2m \leq 2\sum\limits_{i=1}^D \lfloor \frac{A_i}{2} \rfloor =\sum\limits_{i=1}^D A_i -\sum\limits_{i=1}^D (A_i \pmod 2) = n- \sum\limits_{i=1}^D (A_i \pmod 2)
\]
现在问题变成,出现次数为奇数的颜色数小于等于\(2m-n\)
我们设\(g_i\)为恰好有\(i\)个奇数的方案数,则答案就是\(\sum\limits_{i=0}^{2m-n}g_i\)
恰好不好求,我们考虑转化成至少,设\(f_i\)为至少\(i\)个奇数的方案数,有:
\[f_i=\binom{D}{i}n![x^n](\frac{e^x-e^{-x}}{2})^i(e^x)^{D-i}
\]
展开得:
\[\begin{align}
f_i
&=\binom{D}{i}\frac{n!}{2^i}[x^n](e^x-e^{-x})^i(e^x)^{D-i}
\\
&=\binom{D}{i}\frac{n!}{2^i}[x^n](\sum\limits_{k=0}^i \binom{i}{k}e^{xk} (-e^{-x})^{i-k} )e^{D-i}
\\
&=\binom{D}{i}\frac{n!}{2^i}[x^n]\sum\limits_{k=0}^i \binom{i}{k}(-1)^{i-k} e^{(D+2k-2i)x}
\\
&=\binom{D}{i}\frac{1}{2^i}\sum\limits_{k=0}^i \binom{i}{k}(-1)^{i-k} (D+2k-2i)^n
\\
&=\binom{D}{i}\frac{i!}{2^i}\sum\limits_{k=0}^i \frac{(-1)^{i-k}(D+(i-k))^n}{(i-k)!} \times k!
\end{align}
\]
化成这样以后卷积的形式就已经很明显了
再考虑\(f_i\)和\(g_i\)的关系,由于:
\[f_k=\sum\limits_{i=k}^D \binom{i}{k} g_i
\]
二项式反演得:
\[\begin{align}
g_k
&=\sum\limits_{i=k}^D (-1)^{i-k} \binom{i}{k} f_i
\\
&=\frac{1}{k!}\sum\limits_{i=k}^D \frac{(-1)^{i-k}}{(i-k)!} \times f_ii!
\end{align}
\]
也可以卷积
Code
#include<bits/stdc++.h>
#define PR 3
#define mod 998244353
#define LL long long
using namespace std;
LL Ans;
int n,m,D;
int rev[400005];
LL inv[400005],fact[400005],invf[400005];
LL f[400005],g[400005],F[400005],G[400005];
inline LL read(){
LL x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+ch-'0';
ch=getchar();
}
return x*f;
}
inline LL quick_power(LL x,int k){
LL res=1;
while(k){
if(k&1)
res=res*x%mod;
x=x*x%mod;k>>=1;
}
return res;
}
void Initialize(){
inv[1]=1;
fact[0]=invf[0]=1;
fact[1]=invf[1]=1;
for(register int i=2;i<=D;++i){
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
invf[i]=invf[i-1]*inv[i]%mod;
fact[i]=fact[i-1]*i%mod;
}
return;
}
void NTT(LL *F,int Lim,int op){
for(register int i=0;i<Lim;++i){
if(i<rev[i])
swap(F[i],F[rev[i]]);
}
for(register int mid=1;mid<Lim;mid<<=1){
int R=mid<<1;
LL rt=quick_power(PR,(mod-1)/R);
for(register int j=0;j<Lim;j+=R){
LL w=1;
for(register int k=0;k<mid;++k){
LL x=F[j|k],y=w*F[j|k|mid]%mod;
F[j|k|mid]=(x-y+mod)%mod;
F[j|k]=(x+y)%mod;
w=w*rt%mod;
}
}
}
if(op==-1){
reverse(F+1,F+Lim);
LL Inv=quick_power(Lim,mod-2);
for(register int i=0;i<Lim;++i)
F[i]=F[i]*Inv%mod;
}
return;
}
int main(){
int Lim,Len;
D=read();n=read();m=read();
if(n<2*m){
printf("0\n");
return 0;
}
if(n-2*m>=D){
printf("%d\n",quick_power(D,n));
return 0;
}
Initialize();
for(register int i=0;i<=D;++i)
f[i]=((i&1?-1:+1)*invf[i]*quick_power((D-2*i+mod)%mod,n)%mod+mod)%mod;
for(register int i=0;i<=D;++i)
g[i]=invf[i];
Lim=1,Len=-1;
while(Lim<(D+1<<1))
Lim<<=1,++Len;
for(register int i=0;i<Lim;++i)
rev[i]=(rev[i>>1]>>1)|((i&1)<<Len);
NTT(f,Lim,+1);NTT(g,Lim,+1);
for(register int i=0;i<Lim;++i)
f[i]=f[i]*g[i]%mod;
NTT(f,Lim,-1);
for(register int i=0;i<=D;++i)
G[i]=f[i]*fact[i]%mod*fact[D]%mod*invf[D-i]%mod*quick_power(inv[2],i)%mod;
for(register int i=0;i<=D;++i)
F[i]=(((D-i)&1?-1:+1)*invf[D-i]+mod)%mod;
Lim=1,Len=-1;
while(Lim<(D+1<<1))
Lim<<=1,++Len;
for(register int i=0;i<Lim;++i)
rev[i]=(rev[i>>1]>>1)|((i&1)<<Len);
NTT(F,Lim,+1);NTT(G,Lim,+1);
for(register int i=0;i<Lim;++i)
F[i]=F[i]*G[i]%mod;
NTT(F,Lim,-1);
for(register int i=0;i<=n-2*m;++i)
Ans=(Ans+F[D+i]*invf[i]%mod)%mod;
printf("%lld\n",Ans);
return 0;
}