CF1278F Cards

Description

\(m\) 张牌,其中有一张是王牌。将这些牌均匀随机打乱 \(n\) 次,设有 \(x\) 次第一张为王牌,求 \(x^k\) 的期望值。

答案对 \(998244353\) 取模。

Solution

容易知道一次随机后第一张牌为王牌的概率为

\[\begin{align} Pr(X)=\frac{(m-1)!}{m!}=\frac{1}{m} \end{align}\]

那么 \(X^K\) 的期望就为

\[\begin{align} E(X^K)=\sum_{\omega=0}^n Pr(X=\omega) X^K=\sum_{i=0}^n \binom{n}{i}p^i (1-p)^{n-i} i^K=(*) \end{align}\]

此时,通过枚举 \(n\) 我们得到一个 \(O(n)\) 的算法,这可以做 \(n\leq K\) 的情况,但是显然不够优秀。对于 \(n>K\) 的情况,考虑化简式子,根据套路把后面的 \(i^K\) 拆了。

\[\begin{align} (*)&=\sum_{i=0}^n \binom{n}{i} p^i (1-p)^{n-i} \sum_{j=0}^{K} {K \brace j} i^{\underline{j}}\\ &=\sum_{i=0}^n \binom{n}{i} p^i (1-p)^{n-i} \sum_{j=0}^{K} {K \brace j} \binom{i}{j} j! \\ &=\sum_{j=0}^{K} {K \brace j} \sum_{i=j}^n p^i (1-p)^{n-i} \binom{n}{i}\binom{i}{j} j! \\ &=\sum_{j=0}^{K} {K \brace j} \binom{n}{j} j! \sum_{i=j}^n p^i (1-p)^{n-i} \binom{n-j}{i-j} \\ &=\sum_{j=0}^{K} {K \brace j} n^{\underline{j}} p^j \sum_{i=0}^{n-j} p^i (1-p)^{(n-j)-i} \binom{n-j}{i}\\ &=\sum_{j=0}^{K} {K \brace j} n^{\underline{j}} p^j (p+1-p)^{n-j} \\ &=\sum_{j=0}^{K} {K \brace j} n^{\underline{j}} p^j \end{align}\]

复杂度 \(O(K^2)\)


Description

加强版,\(n,m\leq 998244352,K\leq 10^7\)

Solution

依赖于 \(K^2\) 的算法不幸挂掉了,数据范围显然是想让我们线性递推。

这个式子到底慢在哪儿?瓶颈在于求斯特林数,而求斯特林数最快的方法莫过于卷积,然而这也是 \(O(K \log K)\) 的。这就提示我们要把斯特林数给化掉。套用

\[\begin{align} m! {n \brace m}=\sum_{k=0}^m (-1)^{m-k} \binom{m}{k} k^n \end{align} \]

组合数有什么优美性质呢?它可以拆成两项小的组合从而递推,在遇到复杂的求和式子时可以考虑这一方法;它可以快速邻项转移,只要标号是连续的,就能快速转移,套用 \(\binom{n}{i}=\frac{n-i+1}{i}\binom{n}{i-1}\)。运用这两个性质,就能做很多事了。

\[\begin{align} (*)&=\sum_{j=0}^{K} {K \brace j} n^{\underline{j}} p^j \\ &=\sum_{j=0}^K {K \brace j} j! \binom{n}{j} p^j \\ &=\sum_{j=0}^K \binom{n}{j} p^j \sum_{i=0}^j (-1)^{j-i} \binom{j}{i} i^K \\ &=\sum_{i=0}^K i^K \sum_{j=i}^K \binom{n}{j} p^j (-1)^{j-i} \binom{j}{i} \\ &=\sum_{i=0}^K i^K (-1)^i \sum_{j=i}^K \binom{n}{i} \binom{n-i}{j-i} (-p)^j \\ &=\sum_{i=0}^K i^K (-1)^i \binom{n}{i}\sum_{j=0}^{K-i} \binom{K-i}{j} (-p)^{j+i} \\ &=\sum_{i=0}^K p^i \binom{n}{i} i^K \sum_{j=0}^{K-i} \binom{n-i}{j} (-p)^j \end{align} \]

\(f_x=\sum_{j=0}^x \binom{n-K+x}{j}(-p)^j\)

\[\begin{align} (*)=\sum_{i=0}^K p^i \binom{n}{i}i^K f_{K-i} \end{align} \]

前两项都可以通过邻项直接转移,\(i^K\) 是积性函数,可以直接线性筛,现在只需要把 \(f_x\) 快速算出来即可。于是又要用到组合数优美的性质,套用

\[\begin{align} \binom{n}{m}=\binom{n-1}{m}+\binom{n-1}{m-1} \end{align} \]

来得到 \(f_x\) 的递推式,记 \(C=n-K\)

\[\begin{align} f_{x+1}&=\sum_{j=0}^{x+1} \binom{C+x+1}{j}(-p)^j \\ &=1+\sum_{j=0}^{x+1} \Bigg[\binom{C+x}{j}+\binom{C+x}{j-1}\Bigg](-p)^j \\ &=\sum_{j=0}^{x+1} \binom{C+x}{j} (-p)^j + \sum_{j=1}^{x+1} \binom{C+x}{j-1}(-p)^j \\ &=\binom{C+x}{x+1}(-p)^{x+1}+\sum_{j=0}^x \binom{C+x}{j} (-p)^j +\sum_{j=0}^x \binom{C+x}{j}(-p)^{j+1} \\ &=\binom{C+x}{x+1}(-p)^{x+1}+(1-p)f_x \end{align} \]

注意到 \(\binom{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); */
    }
}
posted @ 2021-02-24 21:45  Kreap  阅读(57)  评论(0编辑  收藏  举报