CF1392H. ZS Shuffles Cards

\(n+m\)个球,\(n\)个球上写着互不相同的数字,\(m\)个球为空白。有个初始为空的集合\(S\)。将\(n+m\)个球随机排列。
从前往后操作,求期望操作多少次:

  1. 如果遇到一个数字\(x\),在\(S\)中丢入\(x\);在排列中删去\(x\)
  2. 如果遇到空白:如果\(|S|=n\),则退出;否则重新生成\(n+m\)个球的随机排列。

\(n,m\le 2*10^6\)


好久没有在CF看见推式子题了啊。

一开始看错题意直到发现

原题求最后一个数出现的期望,首先很容易想到minmax容斥,枚举\(T\)算出\(T\)中的某个数第一次出现的期望。设\(k=|T|\)

设生成函数\(G(x)\)表示在做一轮(定义两次重排之间为一轮)的时候,操作\(i\)次退出的概率记在\(x^i\)上。

显然有:

\[G_k(x)=\sum_i\frac{\binom{n-k}{i}i!(n+m-i-1)!m}{(n+m)!}x^{i+1} \]

\(F(x)\)表示这道题的概率生成函数,有:

\(F(x)=\sum_{k=1}^n\binom{n}{k}(-1)^{k-1}\frac{G_0(x)-G_k(x)}{1-G_k(x)}\\=\sum_{k=1}^n\binom{n}{k}(-1)^{k}(\frac{1-G_0(x)}{1-G_k(x)}-1)\\=(\sum_{k=1}^n\binom{n}{k}(-1)^{k}\frac{1}{1-G_k(x)})(1-G_0(x))+1\)

根据概率生成函数的基本性质,有\(E(x)=F'(1)\)。推一波式子之后得到:(注意推导过程中有用到\(G_0(1)=1\)

\[F'(1)=-\sum_{k=1}^{n}\binom{n}{k}(-1)^k\frac{1}{1-G_k(1)}G_0'(1) \]

\(G_0'(1)\)可以线性求。

\(G_k(1)\)考虑组合意义:原来是随机排列满足第一个空白之前,都是在\(T\)之外\(n-k\)个数字的概率。不妨转化成:\(n-k\)个不同球和\(m+k\)个不同标号的球插在一起,\(n-k\)个球内部顺序任意排列,\(m+k\)个球除第一个必须是空白的之外其它任意排列。于是有\(G_k(1)=\frac{\binom{n-k}{n+m}(n-k)!(m+k-1)!m}{(n+m)!}\)。可以\(O(1)\)求。

于是时间复杂度是线性的。


using namespace std;
#include <bits/stdc++.h>
#define N 2000005
#define ll long long
#define mo 998244353
ll qpow(ll x,ll y=mo-2){
	ll r=1;
	for (;y;y>>=1,x=x*x%mo)
		if (y&1)
			r=r*x%mo;
	return r;
}
int n,m;
ll fac[N*2],ifac[N*2];
void initC(int n){
	fac[0]=1;
	for (int i=1;i<=n;++i)
		fac[i]=fac[i-1]*i%mo;
	ifac[n]=qpow(fac[n]);
	for (int i=n-1;i>=0;--i)
		ifac[i]=ifac[i+1]*(i+1)%mo;
}
ll C(int m,int n){return fac[m]*ifac[n]%mo*ifac[m-n]%mo;}
ll iC(int m,int n){return ifac[m]*fac[n]%mo*fac[m-n]%mo;}
ll ans;
int main(){
//	freopen("in.txt","r",stdin);
	scanf("%d%d",&n,&m);
	initC(n+m);
	ll p=0;
	for (int i=0;i<=n;++i)
		(p+=C(n,i)*fac[i]%mo*fac[n+m-i-1]%mo*ifac[n+m]%mo*(i+1))%=mo;
	p=p*m%mo;
	ll s=0;
	for (int k=1;k<=n;++k){
		ll t=0;
//		for (int i=0;i<=n-k;++i)
//			(t+=C(n-k,i)*fac[i]%mo*fac[n+m-i-1]%mo*ifac[n+m])%=mo;
//		t=t*m%mo;
		t=C(n+m,n-k)*fac[n-k]%mo*fac[m+k-1]%mo*m%mo*ifac[n+m]%mo;
		(s+=(k&1?-1:1)*C(n,k)*qpow(1-t))%=mo;
	}
	ll ans=(-s*p%mo+mo)%mo;
	printf("%lld\n",ans);
	return 0;
}
posted @ 2021-01-29 16:34  jz_597  阅读(111)  评论(0编辑  收藏  举报