题意:
一个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}\)
可以发现,这成一个等比数列:
\[ f_0-f_1=1\\ f_1-f_2=m\\ …\\ f_{n-1}-f_n=m^{n-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\n",(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\n",ans);
}
}
}
return 0;
}