题目大意就是对于一个m面的骰子,回答这么两个问题:
1.求连续扔n次都是同一数字的期望次数。
2.求连续扔n次每一次数字都不相同的期望次数。
对于期望dp特别菜的我来说,这道题已经算是很难了。反正是抠了一天……
我们先看第一问。
令fi表示连续 i 次数字都相同的期望,那么要考虑他能转化到什么状态,而不是由什么状态转化过来。
转化到什么状态要考虑到所有情况:包括扔的数字相同的和不同两种情况,于是转移方程就写出来了:
fi = 1 / m * fi+1 + (m - 1) / m * f1.
因为如果扔到的数字不同,就退回到了f1.
然而这个方程是有后效性的,所以变一个形:
fi+1 = m * fi - (m - 1) * f1
还可以再变,相邻两项作差得:
fi+1 - fi = m * (fi - fi-1)
当i = 1时,a1 = f1 = 1
当i >= 2时,令ai = fi - fi-1
于是ai就是一个公比为m的等比数列。
然后很显然
fn = Sn = a1 * (1 - qn) / (1 - q) = (1 - mn) / (1 - m).
用快速幂求解即可。
然后是第二问:
令f[i]表示抛出 i 次不一样的数字的期望,则
fi = (m - i) / m * fi+1 + 1/ m * fi + 1 / m * fi-1 + 1/ m * fi-2 +……+ 1 / m * f1.
因为有1 / m的概率和第fj次是相同的。
然后每一次将fi累加到fn就行了。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<vector> 9 #include<stack> 10 #include<queue> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(' ') 14 #define Mem(a, x) memset(a, x, sizeof(a)) 15 #define rg register 16 typedef long long ll; 17 typedef double db; 18 const int INF = 0x3f3f3f3f; 19 const db eps = 1e-8; 20 const int maxn = 1e6 + 5; 21 22 int T, d, m, n; 23 db dp[maxn]; 24 25 int quickpow(int a, int b) 26 { 27 int ret = 1; 28 while(b) 29 { 30 if(b & 1) ret *= a; 31 a *= a; b >>= 1; 32 } 33 return ret; 34 } 35 36 int main() 37 { 38 while(scanf("%d", &T) != EOF) 39 { 40 while(T--) 41 { 42 scanf("%d%d%d", &d, &m, &n); 43 if(!d) printf("%.9lf ", (db)(quickpow(m, n) - 1) / (db)(m - 1)); 44 else 45 { 46 dp[0] = 1.00; dp[n] = dp[0]; 47 for(rg int i = 1; i < n; ++i) 48 { 49 dp[i] = (db)m / (db)(m - i) * dp[i - 1]; 50 dp[n] += dp[i]; 51 } 52 printf("%.9lf ", dp[n]); 53 } 54 } 55 } 56 return 0; 57 }