HDU 4652 Dice:期望dp(成环)【错位相减】
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4652
题意:
给你一个有m个面的骰子。
两种询问:
(1)"0 m n": “最后n次点数均相同”的投掷次数期望。
(2)"1 m n": “最后n次点数各不相同”的投掷次数期望。
题解:
表示状态:
dp[i] = expectation (当前已经有i个点数相同/不相同)
找出答案:
ans = dp[0]
如何转移:
一、都相同
(1)dp[i] = dp[i+1]/m + dp[1]*(1-1/m) + 1 (要么与前面相同,要么不同)
(2)dp[i+1] = dp[i+2]/m + dp[1]*(1-1/m) + 1 (为了错位相减消去后面的dp[1],令i = i+1)
(1)-(2)得:
dp[i] - dp[i+1] = (dp[i+1] - dp[i+2])/m
设d[i] = dp[i] - dp[i+1],有d[i+1]= dp[i]*m (d[i]可递推)
则:dp[0] - dp[n] = sigma(d[0 to n-1]) (前后两项相消)
又因为:dp[n] = 0
所以:dp[0] = sigma(d[0 to n-1]),枚举求和即可。
二、都不同
(1)dp[i] = dp[i+1]*(m-i)/m + dp[i]/m + dp[i-1]/m +...+ dp[1]/m + 1 (要么与之前均不同,要么与第n,n-1,n-2...1位相同)
(2)dp[i+1] = dp[i+2]*(m-i-1)/m + dp[i+1]/m + dp[i]/m +...+ dp[1]/m + 1 (令i = i+1,错位相减)
(1)-(2)得:
dp[i] - dp[i+1] = (dp[i+1] - dp[i+2])*(m-i-1)/m
设d[i] = dp[i] - dp[i+1],有d[i+1]= dp[i]*m/(m-i-1) (d[i]可递推)
则:dp[0] - dp[n] = sigma(d[0 to n-1])
同一中:dp[0] = sigma(d[0 to n-1]) 即为答案。
AC Code:
1 // PROB 1: is the same 2 // 3 // state expresssion: 4 // dp[i] = expectation 5 // i: the same numbers 6 // 7 // find the answer: 8 // ans = dp[1] + 1 9 // 10 // transferring: 11 // dp[i] = dp[i+1]/m + dp[1]*(1-1/m) + 1 12 // dp[i+1] = dp[i+2]/m + dp[1]*(1-1/m) + 1 13 // dp[i] - dp[i+1] = dp[i+1]/m - dp[i+2]/m 14 // dp[i] - dp[i+1] = (dp[i+1] - dp[i+2])/m 15 // dp[i+1] - dp[i+2] = (dp[i] - dp[i+1])*m 16 // d[0] = dp[0] - dp[1] = 1 17 // dp[0] + dp[n] = sigma(d[0 to n-1]) 18 // dp[0] = sigma(d[0 to n-1]) 19 // 20 // 21 // PROB 2: is different 22 // 23 // state expression: 24 // dp[i] = expectation 25 // i: different numbers 26 // 27 // find the answer: 28 // ans = dp[1] + 1 29 // 30 // transferring: 31 // dp[i] = dp[i+1]*(m-i)/m + dp[i]/m + dp[i-1]/m +...+ dp[1]/m + 1 32 // dp[i+1] = dp[i+2]*(m-i-1)/m + dp[i+1]/m + dp[i]/m +...+ dp[2]/m + dp[1]/m + 1 33 // dp[i] - dp[i+1] = dp[i+1]*(m-i)/m - dp[i+2]*(m-i-1)/m - dp[i+1]/m 34 // dp[i] - dp[i+1] = (dp[i+1] - dp[i+2])*(m-i-1)/m 35 // dp[i+1] - dp[i+2] = (dp[i] - dp[i+1])*m/(m-i-1) 36 // d[0] = dp[0] - dp[1] = 1 37 // dp[0] + dp[n] = sigma(d[0 to n-1]) 38 // dp[0] = sigma(d[0 to n-1]) 39 #include <iostream> 40 #include <stdio.h> 41 #include <string.h> 42 #define MAX_N 1000005 43 44 using namespace std; 45 46 int n,m,p,t; 47 double ans; 48 double dp[MAX_N]; 49 50 void read() 51 { 52 cin>>p>>m>>n; 53 } 54 55 void cal_dp_same() 56 { 57 // dp[i+1] - dp[i+2] = (dp[i] - dp[i+1])*m 58 // dp[0] = sigma(d[0 to n-1]) 59 double d=1; 60 ans=0; 61 for(int i=0;i<n;i++) 62 { 63 ans+=d; 64 d*=m; 65 } 66 } 67 68 void cal_dp_dif() 69 { 70 // dp[i+1] - dp[i+2] = (dp[i] - dp[i+1])*m/(m-i-1) 71 // dp[0] = sigma(d[0 to n-1]) 72 double d=1; 73 ans=0; 74 for(int i=0;i<n;i++) 75 { 76 ans+=d; 77 d*=m/(m-i-1.0); 78 } 79 } 80 81 void solve() 82 { 83 if(p==0) cal_dp_same(); 84 else cal_dp_dif(); 85 } 86 87 void print() 88 { 89 printf("%.9f\n",ans); 90 } 91 92 int main() 93 { 94 while(cin>>t) 95 { 96 while(t--) 97 { 98 read(); 99 solve(); 100 print(); 101 } 102 } 103 }
dp[i] = dp[i+1]*(m-i)/m + dp[i]/m + dp[i-1]/m +...+ dp[1]/m + 1