题意:给定一个 m 面的色子,求连续摇到 n 次相同的点数 和 连续摇到 n 个两两不相同的点数 需要掷色子次数的期望。
分析:推公式题,设 dp[ i ] 为当前已经连续掷出 i 个相同 / 两两不相同的点数的情况下,完成游戏需要掷色子次数的期望。
①:相同
dp[ 0 ] = 1 + dp[ 1 ];
dp[ 1 ] = 1 + 1/m * dp[ 2 ] + (m-1)/m * dp[ 1 ];
dp[ 2 ] = 1 + 1/m * dp[ 3 ] + (m-1)/m * dp[ 1 ];
.....
dp[ i ] = 1 + 1/m * dp[ i+1 ] + (m-1)/m * dp[ 1 ];
dp[ i+1 ] = 1 + 1/m * dp[ i+2 ] + (m-1)/m * dp[ 1 ];
合并第 i 项 和 第 i+1 项 整理得
m * (dp[ i ] - dp[ i+1 ]) = dp[ i+1 ] - dp[ i+2 ] ;
令 d[ i ] = dp[ i ] - dp[ i+1 ] , 则 d[ i+1 ] = m * d[ i ],且 d[ 0 ] = dp[ 0 ] - dp[ 1 ] = 1,所以 d[ i ] = m ^ i , 因为我们需要求的是
dp[ 0 ] , 则 d[ 0 ] + d[ 1 ] + ... + d[ n-1 ] = dp[ 0 ] - dp[ n ] =dp[ 0 ] ( 显然dp[ n ] = 0 ),直接计算即可。
②:不同
dp[ 0 ] = 1 + dp[ 1 ];
dp[ 1 ] = 1 + (m-1)/m * dp[ 2 ] + 1/m * dp[ 1 ];
dp[ 2 ] = 1 + (m-2)/m * dp[ 3 ] + 1/m * (dp[ 2 ] + dp[ 1 ]);
...
dp[ i ] = 1 + (m-i)/m * dp[ i+1 ] + 1/m * (dp[i] + dp[i-1] + ... + dp[ 1 ]);
dp[ i+1 ] = 1 + (m-i-1)/m * dp[ i+2 ] + 1/m * (dp[i+1] + dp[i] + ... + dp[ 1 ] );
合并第 i 项 和 第 i+1 项 整理得
m/(m-i-1) * (dp[ i ] - dp[ i+1 ]) = dp[ i+1 ] - dp[ i+2 ] ;
令 d[ i ] = dp[ i ] - dp[ i+1 ] , 则 d[ i+1 ] = m/(m-i-1) * d[ i ],且 d[ 0 ] = dp[ 0 ] - dp[ 1 ] = 1
则
,
因为我们需要求的是 dp[ 0 ] , 则 d[ 0 ] + d[ 1 ] + ... + d[ n-1 ] = dp[ 0 ] - dp[ n ] =dp[ 0 ] ( 显然dp[ n ] = 0 ),直接计算即可。
代码:
#include<cmath>
#include<cstdio>
#include<iostream>
using namespace std;
double cal1(int m,int n)
{
double ans = 0;
for(int i=0;i<n;i++)
{
ans = ans + pow(m+0.0,i);
}
return ans;
}
double cal2(int m,int n)
{
double ans = 0;
double tmp = 1.0;
for(int i=1;i<=n;i++){
ans+=tmp;
tmp=tmp*m/(m-i);
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int x,n,m;
scanf("%d%d%d",&x,&m,&n);
if(x==0)
{
printf("%.7lf\n",cal1(m,n));
}
else
{
printf("%.7lf\n",cal2(m,n));
}
}
return 0;
}