ZOJ3640 概率DP
Background
If thou doest well, shalt thou not be accepted? and if thou doest not well, sin lieth at the door. And unto thee shall be his desire, and thou shalt rule over him.
And Cain talked with Abel his brother: and it came to pass, when they were in the field, that Cain rose up against Abel his brother, and slew him.
And the LORD said unto Cain, Where is Abel thy brother? And he said, I know not: Am I my brother's keeper?
And he said, What hast thou done? the voice of thy brother's blood crieth unto me from the ground.
And now art thou cursed from the earth, which hath opened her mouth to receive thy brother's blood from thy hand;
When thou tillest the ground, it shall not henceforth yield unto thee her strength; a fugitive and a vagabond shalt thou be in the earth.
—— Bible Chapter 4
Now Cain is unexpectedly trapped in a cave with N paths. Due to LORD's punishment, all the paths are zigzag and dangerous. The difficulty of the ith path is ci.
Then we define f as the fighting capacity of Cain. Every day, Cain will be sent to one of the N paths randomly.
Suppose Cain is in front of the ith path. He can successfully take ti days to escape from the cave as long as his fighting capacity f is larger than ci. Otherwise, he has to keep trying day after day. However, if Cain failed to escape, his fighting capacity would increase ci as the result of actual combat. (A kindly reminder: Cain will never died.)
As for ti, we can easily draw a conclusion that ti is closely related to ci. Let's use the following function to describe their relationship:
After D days, Cain finally escapes from the cave. Please output the expectation of D.
Input
The input consists of several cases. In each case, two positive integers N and f (n ≤ 100, f ≤ 10000) are given in the first line. The second line includes N positive integers ci (ci ≤ 10000, 1 ≤ i ≤ N)
Output
For each case, you should output the expectation(3 digits after the decimal point).
Sample Input
3 1 1 2 3
Sample Output
6.889
题意:
师傅被妖怪抓走了。有n个妖怪,妖怪有一个战斗力c[],师傅初始战斗力F0。每天,师傅会随机选择一个妖怪决斗,如果打得赢Ft>c[],就可以逃出去,逃出去要t[]天;否则,师傅会拿出秘籍练功,将自己变强,F(t+1)=Ft+c[],第二天寻找下一次机会。问师傅逃脱所用天数的数学期望。
思路:
设dp[F]是战斗力为F时,逃离的天数期望。(答案是dp[f])。则有公式。
dp[F]= Σ 1/n * t[i] ,F>c[[i]
+∑ 1/n * dp[F+c[i]] ,F<=c[i]
经验:
数学期望题目大多数需要逆推。 此处逆推的方式是记忆化。而且此题,F是单增的,而且有很明显的边界,即F达到大于最大的C[]的时候,就不会再向下面搜索了,所以记忆化搜索很有效。实在想不出顺推的DP,就记忆化逆推吧,不然DP烧脑壳。
代码:
1 #include"bits/stdc++.h" 2 3 #define db double 4 #define ll long long 5 #define vl vector<ll> 6 #define ci(x) scanf("%d",&x) 7 #define cd(x) scanf("%lf",&x) 8 #define cl(x) scanf("%lld",&x) 9 #define pi(x) printf("%d\n",x) 10 #define pd(x) printf("%f\n",x) 11 #define pl(x) printf("%lld\n",x) 12 #define rep(i, n) for(int i=0;i<n;i++) 13 using namespace std; 14 const int N = 1e6 + 5; 15 const int mod = 1e9 + 7; 16 const int MOD = 998244353; 17 const db PI = acos(-1.0); 18 const db eps = 1e-10; 19 const ll INF = 0x3fffffffffffffff; 20 //int t; 21 db dp[N]; 22 int c[N]; 23 int t[N]; 24 int n,f; 25 db dfs(int u) 26 { 27 if(dp[u]>0) return dp[u]; 28 for(int i=0;i<n;i++){ 29 if(u>c[i]) dp[u]+=1.0*t[i]/n; 30 else dp[u]+=(dfs(u+c[i])+1)/n; 31 } 32 if(u==f) printf("%.3f\n",dp[f]); 33 return dp[u]; 34 } 35 int main() 36 { 37 38 while(scanf("%d%d",&n,&f)==2){ 39 for(int i=0;i<n;i++) ci(c[i]),t[i]=int((1+sqrt(5.0))/2*c[i]*c[i]); 40 memset(dp,0, sizeof(dp)); 41 dfs(f); 42 } 43 return 0; 44 }