【CF1349D】Slime and Biscuits【概率期望】【解方程】

题意:nn个人共有mm个饼干,每轮随机选一个饼干随机给一个另外的人,所有饼干都在一个人手里时游戏结束,求期望进行次数。模998244353998244353

n105,m3×105n\leq10^5,m\leq3\times10^5

首先肯定是每个人作为最终获得所有饼干的人分别考虑。

但是如果只考虑这个人的话,无法确定游戏进行过程中是否已经在其他人那里结束了。

所以干脆改下规则:设当前考虑的人为xx,规定只有xx收集完所有饼干后游戏才结束。也就是有人收集完了所有饼干后,如果他不是xx,游戏继续进行;否则游戏立即结束。

为了后面讲清楚,这里给一个不正式的严谨定义:设R,R1RnR,R_1\sim R_n表示游戏遵循的规则,其中RR表示任何一个人收集了所有饼干后游戏结束,即原来的规则。Rx(x[1,n])R_x(x\in[1,n])表示只有xx收集完游戏才结束的新规则。

设在RxR_x下游戏期望进行的次数为ExE_x'。即:设f(x,i)f'(x,i)表示游戏进行了ii步后结束且xx获得了所有饼干的概率,Ex=i=0if(x,i)E'_x=\sum_{i=0}^{\infin}i\cdot f'(x,i)

注:这个f(x,i)f'(x,i)和后面的f(x,i)f(x,i)只是为了方便理解定义,对推导没有影响。

我们考虑寻找新的规则和原来的规则的联系

RR下,设PxP_x表示游戏结束时所有饼干在xx手上的概率,ExE_x表示所有饼干在xx手上结束的所有情况 的 概率乘以时间 之和。(注意不是期望,概率的分母包括了在其他人那里结束的情况)

即:设f(x,i)f(x,i)表示游戏进行ii步后结束,xx获得所有饼干的概率,Ex=i=0if(x,i),Px=i=0f(x,i)E_x=\sum_{i=0}^{\infin}i\cdot f(x,i),P_x=\sum_{i=0}^\infin f(x,i)

i=1nPi=1,i=1nEi=ans\sum_{i=1}^n P_i=1,\sum_{i=1}^nE_i=ansansans为题目所求

CC表示在RjR_j下,现在所有饼干在ii手上且iji\neq j,游戏期望还要进行多少步。显然这是个与i,ji,j无关的常数。

考虑用ExE_x表示出ExE_x'

为了方便,我们称一个状态为ii类关键点,当且仅当这个状态的所有饼干都在ii手上。

考虑在RxR_x下的一场游戏,如果它只有结束状态这一个关键点,期望步数为ExE_x

否则我们枚举第一个关键点的类别ii,显然ixi\neq x,不然游戏会提前结束。然后从这个关键点开始就是 从“所有点都在ii手上”这个状态开始的RxR_x游戏,期望步数为CC

所以:

Ex=Ex+i=1n[ix](Ei+PiC)E'_x=E_x+\sum_{i=1}^n[i\neq x](E_i+P_iC)

如果你想不通为什么CC要乘上PiP_i:

前面说过,Ex=i=0if(x,i)E_x=\sum_{i=0}^\infin if(x,i)
换句话说,对于每一个ii,都有f(x,i)f(x,i)的可能性在ii步后 所有饼干都在xx手上,在这里就是到达枚举的第一个关键点。
在这之后还需要CC步来到最终结束的状态,即i=0(i+C)f(x,i)\sum_{i=0}^\infin(i+C)f(x,i)
Px=i=0f(x,i)P_x=\sum_{i=0}^{\infin}f(x,i),所以加上PiCP_iC就可以了

拆一下:

Ex=Ex+i=1n[ix](Ei+PiC)E'_x=E_x+\sum_{i=1}^n[i\neq x](E_i+P_iC)

Ex=Ex+i=1n[ix]Ei+i=1n[ix]PiCE'_x=E_x+\sum_{i=1}^n[i\neq x]E_i+\sum_{i=1}^n[i\neq x]P_iC

Ex=i=1nEx+Ci=1n[ix]PiE'_x=\sum_{i=1}^nE_x+C\sum_{i=1}^n[i\neq x]P_i

Ex=ans+C(1px)E'_x=ans+C(1-p_x)

x=1nx=1\sim n求和

i=1nEi=nans+C(n1)\sum_{i=1}^nE'_i=n\cdot ans+C(n-1)

只要求出ExE'_xCC的值,问题就解决了!

CC是严格包含于ExE_x'的,所以我们的目标是解决新规则下的问题。

注意到在RxR_x下,我们并不关心每个饼干具体在谁手上,我们只关心它在不在xx手上

所以可以设f(i)f(i)表示当前xx手上有ii个饼干时期望进行次数。

f(i)={1+1n1f(i+1)+n2n1f(i)x=01+imf(i1)+mim(1n1f(i+1)+n2n1f(i))0<x<m0x=mf(i)= \begin{cases} 1+\frac{1}{n-1}f(i+1)+\frac{n-2}{n-1}f(i)& x=0\\ 1+\frac{i}mf(i-1)+\frac{m-i}{m}(\frac{1}{n-1}f(i+1)+\frac{n-2}{n-1}f(i))& 0<x<m\\ 0 & x=m \end{cases}

解出这个方程就好了

暴力硬推是一种方法,这里有一个很优美的思路:

考虑中间的式子,记为

f(i)=Af(i1)+Bf(i)+Cf(i+1)+1f(i)=Af(i-1)+Bf(i)+Cf(i+1)+1

Af(i1)+(B1)f(i)+Cf(i+1)+1=0Af(i-1)+(B-1)f(i)+Cf(i+1)+1=0

注意到A+B+C=1A+B+C=1,设g(i)=f(i)f(i+1)g(i)=f(i)-f(i+1)

Ag(i1)+(A+B1)g(i)+1=0A\cdot g(i-1)+(A+B-1)g(i)+1=0

g(i)=Ag(i1)+1Cg(i)=\frac{A\cdot g(i-1)+1}{C}

这样推一次就可以把gg算出来,求个后缀和就得到了ff

然后Ex=f(ai),C=f(0)E_x'=f(a_i),C=f(0)

复杂度O(n)O(n)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#define MAXN 300005
using namespace std;
inline int read()
{
	int ans=0;
	char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
const int MOD=998244353;
typedef long long ll;
inline int qpow(int a,int p)
{
	int ans=1;
	while (p)
	{
		if (p&1) ans=(ll)ans*a%MOD;
		a=(ll)a*a%MOD;p>>=1;
	}
	return ans;
}
#define inv(x) qpow(x,MOD-2)
inline int add(const int& x,const int& y){return x+y>=MOD? x+y-MOD:x+y;}
inline int dec(const int& x,const int& y){return x<y? x-y+MOD: x-y;}
int a[MAXN],f[MAXN];
int main()
{
	int n=read(),m=0;
	for (int i=1;i<=n;i++) m+=(a[i]=read());
	f[0]=n-1;
	for (int i=1;i<m;i++) f[i]=((ll)i*inv(m)%MOD*f[i-1]%MOD+1)*m%MOD*(n-1)%MOD*inv(m-i)%MOD;
	for (int i=m;i>=0;i--) f[i]=add(f[i],f[i+1]);
	int sum=0;
	for (int i=1;i<=n;i++) sum=add(sum,f[a[i]]);
	sum=dec(sum,f[0]*(n-1ll)%MOD);
	sum=(ll)sum*inv(n)%MOD;
	cout<<sum;
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章