1. 程式人生 > >2018.11.09【UVA11021】Tribles(概率DP)(不用全概率公式)

2018.11.09【UVA11021】Tribles(概率DP)(不用全概率公式)

傳送門


強烈譴責:

對於懂全概率公式的人來說這是一道水題。

然而就是這群懂全概率公式的人寫著一篇篇題解與程式碼不符的部落格。連遞推陣列 f f 的下標含義都描述的完全錯誤,不是思路不同的問題,因為我照著與他們完全互斥的思路推出了與他們完全相同的公式,而照著他們的思路。。。麻煩懂了全概率之後再來寫題解行嗎。

更不用說什麼"直接根據全概率公式可知"。。。連完備事件集都沒有給出還全概率公式

以上寫題解的方式就是不負責的表現
蒟蒻在經歷了種種不負責任的題解洗禮之後終於推出了一個不用高深的全概率公式的理解方式

思路:

根據乘法原理,每個生物的情況其實是一樣的,所以只需要推出一隻的情況然後 k k 次方就行了。
考慮我們現在知道了一隻生物的家族在 i

i 天及之前完全死亡(包括一個後代都沒有的請款),記為 f i f_i ,顯然有 f 1
= p 0 f_1=p_0
,及第一隻死亡的時候沒有產生任何後代。

然後現在考慮我們知道 f i f_i ,怎麼求出 f i + 1 f_{i+1} ,首先它沒有任何後代的情況要計算,因為算的是 i i 天及之前

然後考慮他產生了某個數量 j j 的後代,概率為 p j p_j ,那麼它的家族要在第 i + 1 i+1 天及之前完全死亡,對於後代來說就是在後代自己的第 i i 天及之前全部死亡。

所以 f i f_i 可以理解為以一隻生物開頭的家族堅持不超過 i i 天的概率,那麼對於後代來說,父親的第 i + 1 i+1 天其實就是它們的第 i i 天,所以可以直接用父親的 f i f_i 來計算。

那麼對於第一隻生物,有如下遞推式 f i = j = 0 n 1 p j × f i 1   j f_i=\sum_{j=0}^{n-1}p_j\times f_{i-1}\text{ }^j


程式碼:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

template<class T>
T quickpow(T a,int b){
	T ans=1;
	while(b){
		if(b&1)ans*=a;
		a=a*a;
		b>>=1;
	}
	return ans;
}

int T,t;
double f[1005];
double p[1005];
signed main(){
	scanf("%d",&T);
	while(T--){
		int n,k,m;
		scanf("%d%d%d",&n,&k,&m);
		for(int re i=0;i<n;++i)scanf("%lf",&p[i]);
		f[1]=p[0];
		for(int re i=2;i<=m;++i){
			f[i]=0;
			for(int re j=0;j<n;++j){
				f[i]+=p[j]*quickpow(f[i-1],j);
			}
		}
		printf("Case #%d: %.7lf\n",++t,quickpow(f[m],k));
	}
	return 0;
}