题意:给定一个m面的色子。投色子,然后问你期望值为多少次时 后n次都相同或后n次都不相同
解题思路:完全YY的,0的话就是关于m的等比数列和,如果是1的话,就是一个类似于秦九韶算法的分数和;;;比赛后八分钟A了。。可惜。
官方:
设dp[i]表示当前在 已经投掷出 i个 不相同/相同 这个状态时期望还需要投掷多少次,然后dp[i] 有如下等式:
相同:
//dp[0] = 1 + dp[1]
//dp[1] = 1 + ((m-1)dp[1] + dp[2]) / m
//dp[i] = 1 + ((m-1)dp[1] + dp[i+1]) / m
//...
//dp[n] = 0;
不相同:
//dp[0] = 1 + dp[1]
//dp[1] = 1 + (dp[1] + (m-1) dp[2]) / m
//dp[2] = 1 + (dp[1] + dp[2] + (m-2) dp[3]) / m
//dp[i] = 1 + (dp[1] + dp[2] + ... dp[i] + (m-i)dp[i+1]) / m
//...
//dp[n] = 0;
。。于是可以高斯消元。。对于第一问。。我们发现就是相当于 Typing Monkey 问题中字符串是 AAAA..AA 这一特殊情况。。解得递推式:
dp[n] = 0
dp[n-1] = dp[n] * m + 1
。。。
解开后等于等比数列求和。
(也可以直接得到这个公式。。。因为在当前状态只有 m/1 的概率可以进入下一状态,否则要重新来过。。而这一步会另总的步数 + 1。)
对于第二问。。
现在设s[i]=sigma{dp[i], 1..i},对s[i] 列方程
每个方程是关于三个相邻的s[i] 的,然后就可以线性时间解出来了。
也可以设 d[i] = dp[i] - dp[i+1].
可以得到 d[i] = m * d[i-1] / (m-i)
然后就是解一元一次方程...
解题代码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 5 long long Pow(int b ,int n) 6 { 7 long long ans = 1 ; 8 9 for(int i = 1;i <= n; i ++) 10 ans *= b; 11 return ans; 12 } 13 long long do1(int b,int n ) 14 { 15 if(b == 1) 16 return 1; 17 return (1-Pow(b,n))/(1-b); 18 } 19 double do2(int n,int k ,int i ) 20 { 21 if(i == k ) 22 return (n*1.0/i); 23 return n*1.0/i*(1 + do2(n,k,i-1)); 24 } 25 int main() 26 { 27 int t; 28 while(scanf("%d",&t) != EOF) 29 { 30 while(t--) 31 { 32 int a, b , c ; 33 scanf("%d %d %d",&a,&b,&c); 34 if(a == 0 ) 35 { 36 printf("%lld.000000000 ",do1(b,c)); 37 } 38 else 39 { 40 printf("%.9f ",do2(b,b-c+1,b)); 41 } 42 } 43 } 44 return 0 ; 45 }