1. 程式人生 > 實用技巧 >概率、期望經過次數、期望在無向圖的一點點應用,以及其的一道應用([SDOI2017]硬幣遊戲)

概率、期望經過次數、期望在無向圖的一點點應用,以及其的一道應用([SDOI2017]硬幣遊戲)

目錄

參考資料

看到期望經過次數的說法:https://blog.csdn.net/bzjr_Log_x/article/details/100007360
你谷題解:https://www.luogu.com.cn/blog/Kelin/solution-p3706

期望經過次數和概率在無向圖之間的聯絡

是不是看到這個頭都要爆炸了。

前言

也許許多時候你總是會看到一些題目,問你最終概率,但是其轉移過程是無向圖的,這個時候,高斯消元大爺肯定是不二之選。(至少我現在還沒有看到哪個無向圖概率題是不用高斯消元的)

正片

現在給你一個這樣的無向圖:

我們從\(0\)號點出發,走到\(1\)的概率是多少(走到\(1\)就停),\(50\%\)停留在原地,也許你會直接說,這不就是\(1\)嗎。

但是如果要你列出概率方程,額。。。。

\(f[i]\)為到達這個點的概率,然後\(f[1]=\frac{1}{2}f[0]\)

但是\(f[0]\)的概率為\(0\),總麼可能轉移的了啊。

這個時候,我們終於發現了一個事情,因為概率這個東西更加反映的是結果,即各個隨機事件之間所發生樣本個數和總樣本個數間的比例,其對於中間過程十分不友好,因為中間過程也許根本連樣本個數都沒有。

於是統計其概率就成了一個十分玄乎的事情。不就是1嗎

事實上,當然對於這個圖也存在微積分的方法,但是當點數很多,終點很多,微積分也許就不是一個好主意了。

但是,這個時候,我們引入一個新的東西,點的期望經過次數,這個就對於中間點十分的友好,因為其中間點也可以有確定的數值,那麼如何統計呢?對於一個點\(x\),如果存在一條路徑可以到\(x\)(假設這個時候突然停下來等一等,畢竟\(x\)不是終點,後面還會繼續跑),那麼就把這條路徑現在的概率乘\(1\)加到\(e[x]\)中(\(e[x]\)表示期望經過次數),當然,一條路徑可能經過\(x\)多次,因此當一條路徑經過\(x\)時,其可能已經經過\(x\)好幾次了。

當然,這也是個無限的東西,他是否是收斂的,我並不會證,但是用高斯消元一樣可以求得,後面會講。

最神奇的一件事情是,\(e[ed]\)就等於\(ed\)的概率。(\(ed\)可能有多個)

仔細觀察就會發現,\(e[ed]\)的定義剛好就是\(ed\)的概率的定義(或者說是經典求法),此時我們前文括號裡說停下來等一等就是永遠停下來了,因為到了\(ed\)就停下來。

發現了這個美妙的性質,無向圖的概率題基本上都可以用期望經過次數來搞了。

無向圖的期望問題

本文無法保證正確性

事實上,期望無非是列個式子,高斯消元。

期望經過次數

本文先講如何求期望經過次數。

需要嚴重注意的事情是:實際上,期望的轉移過程不能但看幾個變數間存在概率關係就直接乘上概率轉移,因為期望在無向圖上之所以有最終答案是因為無限是可以通過求極限得到確值的,比如:期望次數,其只是一坨式子的結果,你不能單單把這個當成次數來耍除非你是老手。在後文,就會舉一個錯誤示範。當然,許多用法都是可以證明是對的,比如下文提到的把邊的期望經過次數轉換為兩端點的期望經過次數。

好,扯了這麼多,關鍵是次數怎麼求你是一句話也沒講啊。這不就來講了嗎。

首先,設\(E(x)\)為到\(x\)的期望經過次數,\(Edge\)為邊集,\(p(x,y)\)為經過這條邊的概率(當然,有時候\(x,y\)走這條邊的概率可能不相同,因此\(p(x,y)≠p(y,x)\)),那麼\(E(y)=\sum\limits_{(x,y)∈Edge,x≠ed}E(x)p(x,y)\)

現在證明在期望具體式子中也是對的。

設存在一條從起點到\(x\)並且停下來一下的路徑\(T\),其目前的概率為\(S\),然後其轉移到\(y\)的概率為\(p(x,y)\),那麼顯然\(T+y\)(就是路徑又多了個\(y\))的概率就是\(S*p(x,y)\),因為\(T\)不重複,所以\(T+y\)也不重複,概率就是所有加起來,也就是\(E(x)*p(x,y)\)

但是,比較特殊的,\(E(1)+=1\),因為從起點出發,必須經過。

而這個統計期望經過次數的,在我的另外一篇期望部落格有進行實踐。應該

期望經過長度

這種題目一般就是邊還有長度,求到達終點的期望經過長度。

這個一般就兩種求法,一種是邊的期望經過次數,可以轉換為兩端點的期望經過次數,還有一種是直接霸王硬上弓。

第一種不講了。

第二種我們考慮像期望經過次數一樣,設\(f(x)\)表示從起點到達\(f(x)\)的期望長度。

那麼\(f(y)=\sum\limits_{(x,y)∈Edge,x≠ed}(f(x)+w(x,y))p(x,y)=\sum\limits_{(x,y)∈Edge,x≠ed}f(x)p(x,y)+w(x,y)p(x,y)\)\(w\)為邊權)。

但是從期望的角度來看,這是錯的。

這裡假設邊權都是\(1\),也就是\(f(y)=\sum\limits_{(x,y)∈Edge,x≠ed}f(x)p(x,y)+p(x,y)\)

存在\(st->x\)的路徑\(T\),以及其概率\(S\),還有其價值\(V\)

那麼理論上:\(T+y\)\(S',V'\)\(S*p(x,y)\)\(V+1\)

根據期望化一下式子:\(S*p(x,y)*(V+1)=S*p(x,y)*V+S*p(x,y)\),而我們發現,\(f(x)*p(x,y)\)其實就是\(S*p(x,y)*V\)

但是\(S*p(x,y)\)嘛,根據乘法分配律:\(p(x,y)\sum\limits_{所有st->x的路徑} S_{每條路徑的概率}\),然後我們發現,這後面不就是\(E(x)\)嗎,但是呢,我們的統計方法是\(p(x,y)\),其實換成\(E(x)\)應該(沒有實踐過)就是對的,但是\(p(x,y)\)絕對錯。(事實上,你可以發現,如果邊權全部為\(0\),初始\(V\)\(1\),這其實就是求期望經過次數)

因此,期望的東西不能光憑感覺行事實際上屑作者也沒有實踐過,如果你不是搞期望的老司機,最好不要在沒有根據的情況亂搞式子。

但是,如果我們設\(f(x)\)為到達\(ed\)的期望長度,以\(f(st)\)為答案的話,那麼,式子就變成了:\(f(x)=\sum\limits_{(x,y)∈Edge}(f(y)+w(x,y))p(x,y)=\sum\limits_{(x,y)∈Edge}f(y)p(x,y)+w(x,y)p(x,y)\),其中\(f(ed)=0\)

那麼這個是不是對的呢?

存在\(y->ed\)的路徑\(T\),以及其概率\(S\),還有其價值\(V\)

那麼理論上:\(x+T\)\(S',V'\)\(S*p(x,y)\)\(V+w(x,y)\)

根據期望化一下式子:\(S*p(x,y)*(V+w(x,y))=S*p(x,y)*V+S*p(x,y)*w(x,y)\),而我們發現,\(f(x)*p(x,y)\)其實還是\(S*V*p(x,y)\),但是\(S*p(x,y)*w(x,y)\),把所有路徑的\(S\)加起來,它等於多少呢?不難發現,這個總和其實就是從\(y\)到達\(ed\)的概率,顯然根據洛必達法則其實就是顯然,因為到\(ed\)才停,所以最後一定會到達\(ed\),所以概率為\(1\),所以最終和為\(p(x,y)*w(x,y)\),WOC,真的對了。

從此不難看出,因為從\(ed\)\(st\)推起的期望有一個很重要的性質,就是每個點到\(ed\)的概率都為\(1\),所以在做期望的時候,如果到\(ed\)就停,可以優先考慮從\(ed\)推起,思維難度可能會比較小應該吧

其他的無向圖期望自己推吧,這裡只是講講期望概率的誤區,以及一種比較直觀的理解方法。

[SDOI2017]硬幣遊戲

題目

題目

做法

事實上,這個只是幫助理解概率的應用問題的。

TLE做法

如果你對無向圖期望認識比較淺,建議去多受點題目的折磨,簡稱刷題

這道題目求概率,嘗試從期望經過次數入手。

首先,建立\(AC\)機。

對於\(x\)節點的兩個兒子(這裡\(AC\)機用了兒子優化,即如果一個點沒有這個兒子,會自動填入\(fail\)的兒子到這個兒子位置)建立期望轉移方程(其實就是單源多匯求期望經過次數),由於用了優化的\(AC\)機(這裡必須要用了優化的\(AC\)機,因為每個點必須要有兩個兒子。),所以是有向有環圖(可能無環),處理起來其實跟無向圖沒什麼區別,處理方法就不贅述了,因此節點個數為\(nm\),時間複雜度:\(O((nm)^3)\),只能過\(4\)個點。

但是這裡其實有個優化,理論能過\(70\)分,就是因為每個點只會出現在兩條方程,不難發現,在消掉第\(i\)項時,第\(i\)個方程到第\(n\)個方程中每個點也最多隻會出現在兩條方程中,於是可以優化到\(O((nm)^2)\),可以過\(7\)個點吧,應該。

證明:根據數學歸納法,假設第\(j\)個方程到第\(n\)個方程之間每個點最多隻出現了兩次(也就是隻有兩條方程中這個點的係數不為\(0\)),那麼在消掉第\(j\)項時,因為每個點最多隻出現兩次,所以第\(j\)個方程只與第\(i\)個方程進行消元,藍框框就表示點係數的轉移,不難發現,第\(j+1\)個方程到第\(n\)個方程,藍框框依舊最多兩個,由於一開始就滿足假設,歸納法證畢。

優化

其實不能叫優化,已經是全新做法了。

甚至和\(AC\)機也沒啥關係。

因為發現,在\(AC\)機中,除了\(ed\)以外,其餘的點我們根本就不需要他們的期望經過次數,考慮合多為\(1\),化成\(n+1\)條方程。

現在約定:\(A+B\),就是把\(B\)串放到\(A\)串後面形成的串,模式串就是那群人猜的串,\(f(X)\)表示出現\(X\)模式串的概率,實際也就是包含\(X\)的串的期望經過次數。

現在用\(0/1\)串代替\(TH\),顯然,一個長度為\(n\)且不含任何模式串的串出現概率為\(\frac{1}{2^n}\),實際上也就是期望出現次數(因為,在串後面加\(0/1\)的期望經過次數轉移可以寫成二叉樹來轉移,一個點的期望經過次數為其父親的\(\frac{1}{2}\),第\(n\)層表示長度為\(n\)的串,而一個點的期望等於其左右兒子的期望之和)。

有人說,但是不是有\(ed\)嗎,但是你考慮一下,如果到了\(ed\)繼續跑,那麼概率是不是\(\frac{1}{2^n}\),只不過到了\(ed\)繼續跑的串我們不去問他的概率,而且對於一個串\(N+A\)\(N+A\)的串只在最後含\(A\),且\(N\)不含任何模式串,\(A\)為模式串),設後面的串為\(T\)\(N+A+T\)的長度為\(n\),我們把\(N+A+T\)的概率全部加起來,很明顯就是等於\(N+A\)的概率,所以這樣變形,概率也並不會變,只是幫助證明罷了。

現在設不含任何模式串的串的集合為\(S\)(空串當然也包含在內),當然,下文為了方便,直接用\(S\)表示\(S\)的元素,\(f(S)\)表示\(S\)集合中所有元素的期望出現次數,\(|S|\)\(S\)元素的長度。

考慮尋找\(S\)和每個模式串的關係。

對於任意一個包含\(A\)的串,實際就是用\(S+A\)拼接而成的,而且所有的包含\(A\)的串都可以這樣表示。

但是是不是意味著\(f(X)=\frac{1}{2^m}f(S)\),錯!!!

比如\(A=01,B=00\)

\(S+A=S+01\)

但是如果\(S=S'+0\),那麼\(S+A=S'+001=S'+B+1\),這樣\(B\)不就出現過了嗎,所以\(f(B)\)也就有可能慘一腳,所以就變成了\(f(X)+???=\frac{1}{2^m}f(S)\)

但是這慘一JO的程度有多大呢?

這裡證明,如果\(A\)長度為\(a\)的字首等於\(B\)長度為\(a\)的字尾,那麼\(f(B)\)慘一腳的程度為\(f(B)*\frac{1}{2^{m-a}}\)

\(S=S'+B長度為a的字首\)\(T\)\(A\)長度為\(a\)的字尾。

為什麼\(S'+B+T\)\(B\)慘一腳的程度為\(f(B)*\frac{1}{2^{m-a}}\)

實際上,你有沒有考慮過\(S'+B\)最先出現的也不是\(B\),但是鑑於\(S\)中不含任何模式串,所以,\(S'+B\)中先出了\(C\)串,而\(B\)的字首等於\(C\)的字尾,那麼\(C\)的最後一個字元一定出現在\(S+A\)\(A\)串區間中,所以\(C\)的字尾也等於\(B\)的字首,在統計\(C\)時會被統計到。

所以,\(f(B)*\frac{1}{2^{m-a}}\)實際上加上的時\(S'+B\)\(B\)時唯一模式串的情況,也就是\(f(B)\),但是為什麼要乘\(\frac{1}{2^{m-a}}\),廢話,一個長度為\(|S|+m\),一個長度為\(|S'|+m\),具有可比性嗎,我們的目的是為了把摻一腳的程度加上,使其不再\(f(A)\)中統計,而不是單純的把\(f(B)\)加上,自然需要乘\(\frac{1}{2^{m-a}}\),串的表現就是\(S'+B+T\)才等於\(S+A\),樹的表現就是要讓\(S'+B\)所在點的位置等於\(S+A\)的位置(乘\(\frac{1}{2^{m-a}}\)讓層數相同,\((S+A)\)一定在\((S'+B)\)的子樹內)。

當然,一個字串是可以多摻幾腳的,誰說\(A\)字首等於\(B\)字尾的\(a\)只能有一個。

公式則為:\(f(A)+\sum\limits_{B是模式串}\sum\limits_{a=1}^m[A長度為\)a\(的字首等於\)B\(長度為\)a\(的字尾]f(B)*\frac{1}{2^{m-a}}=f(S)*\frac{1}{2^m}\)(其中\([x]\)\(x\)成立,\([x]=1\),不成立,\([x]=0\)

當然,這裡只有\(n\)條公式,我們發現所有的模式串的概率加起來為\(1\),所以就是\(\sum\limits_{A是模式串}f(A)=1\)

這樣就有\(n+1\)條方程了。

匹配字首字尾後Hash。

時間複雜度:\(O(n^3)\)

#include<cstdio>
#include<cstring>
#include<algorithm>
#define  N  310
using  namespace  std;
typedef  long  long  LL;
template<class  T>
inline  T  zabs(T  x){return  x>=0?x:-x;}
char  st[N][N];
LL  has[N][N],ta=235,tb=1e9+7,fc[N];
inline  LL  find_hash(LL  *ha,int  l,int  r){return  (ha[r]-(ha[l-1]*fc[r-l+1])%tb+tb)%tb;}
int  n,m;
long  double  erfen[N];
long  double  f[N][N],ans[N];
void  GSXY()
{
	n++;
	for(int  i=1;i<=n;i++)
	{
		int  id=i;
		for(int  j=i+1;j<=n;j++)
		{
			if(zabs(f[j][i])>zabs(f[id][i]))id=j;
		}
		if(id!=i)swap(f[id],f[i]);
		for(int  j=i+1;j<=n;j++)
		{
			double  bili=f[j][i]/f[i][i];
			for(int  k=n+1;k>=i;k--)f[j][k]-=f[i][k]*bili;
		}
	}
	for(int  i=n;i>=1;i--)
	{
		ans[i]=f[i][n+1]/f[i][i];
		for(int  j=i-1;j>=1;j--)f[j][n+1]-=ans[i]*f[j][i];
	}
	n--;
}
int  main()
{
	scanf("%d%d",&n,&m);
	fc[0]=1;for(int  i=1;i<=m;i++)fc[i]=fc[i-1]*ta%tb;
	erfen[0]=1;for(int  i=1;i<=m;i++)erfen[i]=erfen[i-1]*0.5;
	for(int  i=1;i<=n;i++)scanf("%s",st[i]+1);
	for(int  i=1;i<=n;i++)
	{
		for(int  j=1;j<=m;j++)has[i][j]=(has[i][j-1]*ta+st[i][j]-'A'+1)%tb/*這裡如果不加1,可能會使程式碼很難辨析AAB和AB*/;
	}
	for(int  i=1;i<=n;i++)
	{
		f[i][n+1]=-erfen[m];
		for(int  j=1;j<=n;j++)
		{
			for(int  k=1;k<=m;k++)
			{
				if(find_hash(has[j],m-k+1,m)==find_hash(has[i],1,k))f[i][j]+=erfen[m-k];
			}
		}
	}
	f[n+1][n+2]=1;for(int  i=1;i<=n;i++)f[n+1][i]=1;
	GSXY();
	for(int  i=1;i<=n;i++)printf("%Lf\n",ans[i]);
	return  0;
}

小結

概率期望真美妙。