CF1392H. ZS Shuffles Cards
有\(n+m\)个球,\(n\)个球上写着互不相同的数字,\(m\)个球为空白。有个初始为空的集合\(S\)。将\(n+m\)个球随机排列。
从前往后操作,求期望操作多少次:
- 如果遇到一个数字\(x\),在\(S\)中丢入\(x\);在排列中删去\(x\)。
- 如果遇到空白:如果\(|S|=n\),则退出;否则重新生成\(n+m\)个球的随机排列。
\(n,m\le 2*10^6\)
好久没有在CF看见推式子题了啊。
一开始看错题意直到发现
原题求最后一个数出现的期望,首先很容易想到minmax容斥,枚举\(T\)算出\(T\)中的某个数第一次出现的期望。设\(k=|T|\)。
设生成函数\(G(x)\)表示在做一轮(定义两次重排之间为一轮)的时候,操作\(i\)次退出的概率记在\(x^i\)上。
显然有:
设\(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\))
\(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;
}