Link
Description
有 (m) 张牌,其中有一张是王牌。将这些牌均匀随机打乱 (n) 次,设有 (x) 次第一张为王牌,求 (x^k) 的期望值。
答案对 (998244353) 取模。
Solution
容易知道一次随机后第一张牌为王牌的概率为
[egin{align}
Pr(X)=frac{(m-1)!}{m!}=frac{1}{m}
end{align}]
那么 (X^K) 的期望就为
[egin{align}
E(X^K)=sum_{omega=0}^n Pr(X=omega) X^K=sum_{i=0}^n inom{n}{i}p^i (1-p)^{n-i} i^K=(*)
end{align}]
此时,通过枚举 (n) 我们得到一个 (O(n)) 的算法,这可以做 (nleq K) 的情况,但是显然不够优秀。对于 (n>K) 的情况,考虑化简式子,根据套路把后面的 (i^K) 拆了。
[egin{align}
(*)&=sum_{i=0}^n inom{n}{i} p^i (1-p)^{n-i} sum_{j=0}^{K} {K race j} i^{underline{j}}\
&=sum_{i=0}^n inom{n}{i} p^i (1-p)^{n-i} sum_{j=0}^{K} {K race j} inom{i}{j} j! \
&=sum_{j=0}^{K} {K race j} sum_{i=j}^n p^i (1-p)^{n-i} inom{n}{i}inom{i}{j} j! \
&=sum_{j=0}^{K} {K race j} inom{n}{j} j! sum_{i=j}^n p^i (1-p)^{n-i} inom{n-j}{i-j} \
&=sum_{j=0}^{K} {K race j} n^{underline{j}} p^j sum_{i=0}^{n-j} p^i (1-p)^{(n-j)-i} inom{n-j}{i}\
&=sum_{j=0}^{K} {K race j} n^{underline{j}} p^j (p+1-p)^{n-j} \
&=sum_{j=0}^{K} {K race j} n^{underline{j}} p^j
end{align}]
复杂度 (O(K^2))
Link
Description
加强版,(n,mleq 998244352,Kleq 10^7)
Solution
依赖于 (K^2) 的算法不幸挂掉了,数据范围显然是想让我们线性递推。
这个式子到底慢在哪儿?瓶颈在于求斯特林数,而求斯特林数最快的方法莫过于卷积,然而这也是 (O(K log K)) 的。这就提示我们要把斯特林数给化掉。套用
[egin{align}
m! {n race m}=sum_{k=0}^m (-1)^{m-k} inom{m}{k} k^n
end{align}
]
组合数有什么优美性质呢?它可以拆成两项小的组合从而递推,在遇到复杂的求和式子时可以考虑这一方法;它可以快速邻项转移,只要标号是连续的,就能快速转移,套用 (inom{n}{i}=frac{n-i+1}{i}inom{n}{i-1})。运用这两个性质,就能做很多事了。
[egin{align}
(*)&=sum_{j=0}^{K} {K race j} n^{underline{j}} p^j \
&=sum_{j=0}^K {K race j} j! inom{n}{j} p^j \
&=sum_{j=0}^K inom{n}{j} p^j sum_{i=0}^j (-1)^{j-i} inom{j}{i} i^K \
&=sum_{i=0}^K i^K sum_{j=i}^K inom{n}{j} p^j (-1)^{j-i} inom{j}{i} \
&=sum_{i=0}^K i^K (-1)^i sum_{j=i}^K inom{n}{i} inom{n-i}{j-i} (-p)^j \
&=sum_{i=0}^K i^K (-1)^i inom{n}{i}sum_{j=0}^{K-i} inom{K-i}{j} (-p)^{j+i} \
&=sum_{i=0}^K p^i inom{n}{i} i^K sum_{j=0}^{K-i} inom{n-i}{j} (-p)^j
end{align}
]
记 (f_x=sum_{j=0}^x inom{n-K+x}{j}(-p)^j)
[egin{align}
(*)=sum_{i=0}^K p^i inom{n}{i}i^K f_{K-i}
end{align}
]
前两项都可以通过邻项直接转移,(i^K) 是积性函数,可以直接线性筛,现在只需要把 (f_x) 快速算出来即可。于是又要用到组合数优美的性质,套用
[egin{align}
inom{n}{m}=inom{n-1}{m}+inom{n-1}{m-1}
end{align}
]
来得到 (f_x) 的递推式,记 (C=n-K)。
[egin{align}
f_{x+1}&=sum_{j=0}^{x+1} inom{C+x+1}{j}(-p)^j \
&=1+sum_{j=0}^{x+1} Bigg[inom{C+x}{j}+inom{C+x}{j-1}Bigg](-p)^j \
&=sum_{j=0}^{x+1} inom{C+x}{j} (-p)^j + sum_{j=1}^{x+1} inom{C+x}{j-1}(-p)^j \
&=inom{C+x}{x+1}(-p)^{x+1}+sum_{j=0}^x inom{C+x}{j} (-p)^j +sum_{j=0}^x inom{C+x}{j}(-p)^{j+1} \
&=inom{C+x}{x+1}(-p)^{x+1}+(1-p)f_x
end{align}
]
注意到 (inom{C+x}{x+1}) 的下标是连续的,所以可以邻项递推,那么 (f_x) 也可以递推了。
复杂度 (O(K))
#include<stdio.h>
#define N 10000007
#define ll long long
#define Mod 998244353
ll qpow(ll x,ll y){
ll ret=1,cnt=0;
while(y>=(1ll<<cnt)){
if(y&(1ll<<cnt)) ret=ret*x%Mod;
x=x*x%Mod,cnt++;
}
return ret;
}
ll n,m,K,inc[N],f[N],i_K[N];
bool mk[N];
int pr[N],cnt=0;
int pre_work(int lim){
inc[1]=i_K[1]=1;
for(int i=2;i<=lim;i++)
inc[i]=(Mod-inc[Mod%i]*(Mod/i)%Mod)%Mod;
for(int i=2;i<=lim;i++){
if(!mk[i]){
pr[++cnt]=i;
i_K[i]=qpow(i,K);
}
for(int j=1;j<=cnt&&pr[j]*i<=lim;j++){
mk[pr[j]*i]=1;
i_K[pr[j]*i]=i_K[pr[j]]*i_K[i]%Mod;
if(i%pr[j]==0) break;
}
}
return 0;
}
int main(){
scanf("%lld%lld%lld",&n,&m,&K);
ll p=qpow(m,Mod-2),ans=0;
if(n<=K){
pre_work(n);
ll ret=qpow(1-p+Mod,n),p1=p*qpow(1-p+Mod,Mod-2)%Mod;
for(int i=1;i<=n;i++){
ret=ret*p1%Mod*(n-i+1)%Mod*inc[i]%Mod;
ans=(ans+ret*i_K[i]%Mod)%Mod;
}
printf("%lld",ans);
}else{
pre_work(K);
ll c=n-K,ans=0,ret=1; f[0]=1;
for(int i=1;i<=K;i++){
ret=ret*(Mod-p)%Mod*(c+i-1)%Mod*inc[i]%Mod;
f[i]=(f[i-1]*(1-p+Mod)%Mod+ret)%Mod;
}
ret=1;
for(int i=0;i<=K;i++){
if(i) ret=ret*p%Mod*(n-i+1)%Mod*inc[i]%Mod;
ans=(ans+ret*i_K[i]%Mod*f[K-i]%Mod)%Mod;
}
printf("%lld",ans);
/* for(int i=1;i<=K;i++)
f[i]=(f[i-1]*(1-p+Mod)%Mod+C(c+i-1,i)*qpow(Mod-p,i)%Mod)%Mod;
for(int i=0;i<=K;i++)
ans=(ans+qpow(p,i)*C(n,i)%Mod*i_K[i]%Mod*f[K-i]%Mod)%Mod;
printf("%lld",ans); */
}
}