CF1278F Card【斯特林数】

CF1278F Card

\(m\) 张牌,其中一个是王牌,你有 \(n\) 次操作,每次进行洗牌并查看第一张牌,记第一张是王牌的次数是 \(x\),求 \(x^k\) 的期望。

\(n,m\le 10^9,k\le 5000\)

类似的普通幂,先枚举底数 \(x\)

\[\begin{aligned} ans &= \sum_{i=0}^n\binom{n}{i}(\frac{1}{m})^i(\frac{m-1}{m})^{n-i}\times i^k ...(1) \\ &=\frac{1}{m^n}\sum_{i=0}^n i^k\binom{n}{i}(m-1)^{n-i} \\ &=\frac{1}{m^n}\sum_{i=0}^n\binom{n}{i}(m-1)^{n-i}\sum_{j=0}^k {k\brace j}i^{\underline j}...(2) \\ &=\frac{1}{m^n}\sum_{j=0}^k{k\brace j}\sum_{i=0}^n\binom{n}{i}(m-1)^{n-i}i^{\underline j}...(3) \\ &=\frac{1}{m^n}\sum_{j=0}^k{k\brace j}\sum_{i=0}^n\binom{n}{i}(m-1)^{n-i}\binom{i}{j}j! \\ &=\frac{1}{m^n}\sum_{j=0}^k{k\brace j}j!\sum_{i=0}^n\binom{n}{i}\binom{i}{j}(m-1)^{n-i} \\ &=\frac{1}{m^n}\sum_{j=0}^k{k\brace j}j!\sum_{i=0}^n\binom{n}{j}\binom{n-j}{i-j}(m-1)^{n-i}...(4) \\ &=\frac{1}{m^n}\sum_{j=0}^k{k\brace j}\binom{n}{j}j!\sum_{i=0}^n\binom{n-j}{n-i}(m-1)^{n-i}\cdot 1 \\ &=\frac{1}{m^n}\sum_{j=0}^k{k\brace j}n^{\underline j}\times m^{n-j} \end{aligned} \]

一些常用技巧:提取公因数化简、交换求和符号、下降幂写成阶乘乘以组合数、组合数恒等变化,二项式反演。

至此,第二类斯特林数可以在 \(O(k^2)\) 时间内预处理得到,总复杂度 \(O(k^2)\)

若用生成函数计算一行的斯特林数可以优化到 \(O(k\log k)\),不过依旧有做到 \(O(k)\) 的科技,可见此题加强版。

#include <bits/stdc++.h>
#define int long long
#define pii pair<int,int>
#define fi first
#define se second
using namespace std;
int read(){
	char c=getchar();int h=0,tag=1;
	while(!isdigit(c)) tag=(c=='-'?-1:1),c=getchar();
	while(isdigit(c)) h=(h<<1)+(h<<3)+(c^48),c=getchar();
	return h*tag;
}
void fil(){
	freopen("data.in","r",stdin);
	freopen("data.out","w",stdout);
}
const int N=5005,mod=998244353;
int brace[N][N];
int fac[N],inv[N];
int ksm(int a,int b) {
	if(b==1) return a%mod;
	int s=ksm(a,b/2);s=s*s%mod;
	if(b%2==1) s=s*a%mod;
	return s%mod;
}
int binom(int n,int m) {
	if(m<0||n<m) return 0;
	return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int calc(int n,int m) {
	int res=1;
	for(int i=n;i>=n-m+1;i--) res=res*i%mod;
	return res;
}
int underpow[N],ppow[N];
signed main(){
//	fil();
	int n=read(),m=read(),k=read();
	brace[0][0]=1;
	for(int i=1;i<=k;i++) {
		for(int j=1;j<=i;j++) {
			brace[i][j]=(j*brace[i-1][j]%mod+brace[i-1][j-1])%mod;
		} 
	}
	underpow[0]=n;
	for(int i=1;i<=k;i++) underpow[i]=underpow[i-1]*(n-i)%mod;
	inv[0]=1,fac[0]=1;
	for(int i=1;i<=N-100;i++) fac[i]=fac[i-1]*i%mod,inv[i]=ksm(fac[i],mod-2)%mod;	
	int res=ksm(ksm(m,n)%mod,mod-2)%mod;
	ppow[0]=ksm(m,n)%mod;
	for(int i=1;i<=k;i++) ppow[i]=ppow[i-1]*ksm(m,mod-2)%mod;
	int sum=0;
	for(int j=0;j<=k;j++) {
		sum+=brace[k][j]*calc(n,j)%mod*ppow[j]%mod;
		sum%=mod;
	}
//	cout<<res<<" "<<sum<<endl;
	cout<<(res*sum%mod)<<endl;
	return 0;
}
posted @ 2024-08-26 18:09  Apricity8211  阅读(5)  评论(0编辑  收藏  举报