题意:
一个m边形的骰子,求连续投出n个相同的面,和m个两两不同的面的期望次数。
solution:
令(f_i)表示已经连续投出i个相同的面,到连续投出n个还需要的期望次数.
令(g_i)类似的表示第二种问题的期望次数。
对于(f_i) ,有两种情况:
① 投出了和前i个相同的面,转移到了(f_{i+1}) ,那么(f_i+=(f_{i+1}+1)*frac{1}{m})
② 投出了一个不同的面,转移到了(f_1),那么(f_i+=(f_1+1)*frac{m-1}{m})
综上,(f_i=(f_{i+1}+1)*frac{1}{m}+(f_1+1)*frac{m-1}{m}=f_{i+1}*frac{1}{m}+f_1*frac{m-1}{m}+1)
继续整理得到:(m*f_i=m+(m-1)*f_1+f_{i+1})
同理的话有:(m*f_{i+1}=m+(m-1)*f_1+f_{i+2})
两式相减得到:(m*(f_{i+1}-f_i)=f_{i+2}-f_{i+1})
可以发现,这成一个等比数列:
运用等比数列求和公式可得:(ans=frac{m*(1-m^{n-1})}{1-m}+1) 。
对于(g_i):
① 投出了和前i个都不同的面,转移到了(g_{i+1}) ,那么(g_i+=(g_{i+1}+1)*frac{m-i}{m})
② 投出了以前出现过的面,那么可能转移到了(g_1,g_2,…g_i),那么(g_i+=sum_{1≤j≤i}{(g_j+1)*frac{1}{m}})
综上,(g_i=(g_{i+1}+1)*frac{m-i}{m}+sum_{1≤j≤i}{(g_j+1)*frac{1}{m}}=g_{i+1}*frac{m-i}{m}+frac{1}{m}*sum_{1≤j≤i}{g_j}+1)
同上面(f_i)类似的处理之后,可以同样的得到(g_i-g_{i+1}=frac{m}{m-i}*(g_{i+1}-g_{i+2})),直接递推一下即可。
code:
#include<cmath>
#include<string>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define RG register
#define IL inline
#define LL long long
#define DB double
using namespace std;
const int N=1e6+1;
int n,m;
DB ans,s[N];
IL int qpow(int x,int p) {
RG int ans=1;
for(;p;p>>=1,x*=x)
if(p&1) ans*=x;
return ans;
}
int main()
{
RG int i,T,typ;
while(scanf("%d",&T)!=EOF) {
while(T--) {
scanf("%d%d%d",&typ,&n,&m);
if(typ==0) printf("%.9lf
",(DB)n*(1-qpow(n,m-1))/(1-n)+1);
else {
ans=0,s[0]=1;
for(i=1;i<m;++i) s[i]=s[i-1]*n/(n-i);
for(i=0;i<m;++i) ans+=s[i];
printf("%.9lf
",ans);
}
}
}
return 0;
}