【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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章