Dice
t组询问,有一个有n个面的色子,现在有两种询问
- 询问最后m次抛色子的实验结果互相相同的抛色子的期望次数。
- 询问最后m次抛色子的实验结果互不不同的抛色子的期望次数。
\(1≤m,n≤10^6\)
解
注意到样本空间无限大,于是考虑无后效性递推做法,设\(E(n)\)表示满足对应询问的抛色子的期望数。
询问1:
不难有
\[E(0)=E(1)+1
\]
\[E(1)=E(2)\frac{1}{n}+E(1)\frac{n-1}{n}+1
\]
\[E(2)=E(3)\frac{1}{n}+E(1)\frac{n-1}{n}+1
\]
\[...
\]
\[E(m-1)=E(m)\frac{1}{n}+E(1)\frac{n-1}{n}+1
\]
\[E(m)=0
\]
注意到类似数列形式,想办法用数列的等差数列法推通项公式,于是有
\[E(i)=E(i+1)\frac{1}{n}+E(1)\frac{n-1}{n}+1
\]
\[E(i+1)=E(i+2)\frac{1}{n}+E(1)\frac{n-1}{n}+1
\]
两式相减,我们有
\[E(i+1)-E(i)=\frac{1}{n}(E(i+2)-E(i+1))
\]
\[E(i+2)-E(i+1)=n\times[E(i+1)-E(i)]
\]
对右式无限递归,而我们又有\(E(1)-E(0)=-1\),所以
\[E(i+1)-E(i+2)=n^{i+1}
\]
所以,我们有
\[E(0)-E(1)=1
\]
\[E(1)-E(2)=n
\]
\[E(2)-E(3)=n^2
\]
\[E(3)-E(4)=n^3
\]
\[...
\]
\[E(m-1)-E(m)=n^{m-1}
\]
累加我们有
\[E(0)=1+n+...+n^{m-1}=\frac{n^m-1}{n-1}
\]
以此跑快速幂即可。
询问2:
同样不难推出
\[E(0)=E(1)+1
\]
\[E(1)=E(2)\frac{n-1}{n}+E(1)\frac{1}{n}+1
\]
\[E(2)=E(3)\frac{n-2}{n}+[E(1)+E(2)]\frac{1}{n}+1
\]
\[...
\]
\[E(m-1)=E(m)\frac{n-m+1}{n}+[E(1)+E(2)+...E(m-1)]\frac{1}{n}+1
\]
同样考虑等差,于是我们设出
\[E(i)=E(i+1)\frac{n-i}{n}+[E(1)+...+E(i)]\frac{1}{n}+1
\]
\[E(i+1)=E(i+2)\frac{n-i-1}{n}+[E(1)+...+E(i+1)]\frac{1}{n}+1
\]
相减我们有
\[E(i+1)-E(i)=E(i+2)\frac{n-i-1}{n}-E(i+1)\frac{n-i}{n}+E(i+1)\frac{1}{n}
\]
\[E(i+1)-E(i)=E(i+2)\frac{n-i-1}{n}-E(i+1)\frac{n-i-1}{n}
\]
\[E(i+1)-E(i)=[E(i+2)-E(i+1)]\frac{n-i-1}{n}
\]
\[E(i+2)-E(i+1)=\frac{n}{n-i-1}[E(i+1)-E(i)]
\]
同样无限递归我们有
\[E(i+2)-E(i+1)=-\frac{n^{i+1}}{(n-i-1)(n-i)...(n-1)}
\]
于是我们有
\[E(0)-E(1)=1
\]
\[E(1)-E(2)=\frac{n}{n-1}
\]
\[E(2)-E(3)=\frac{n^2}{(n-1)(n-2)}
\]
\[...
\]
\[E(m-1)-E(m)=\frac{n^{m-1}}{(n-1)(n-2)...(n-m+1)}
\]
累加我们即可以得到\(E(0)\)的值,以此\(O(n)\)累加即可。
参考代码:
#include <iostream>
#include <cstdio>
#define il inline
#define ri register
using namespace std;
il void fpen(double,int),pen(int);
il double pow(double,int),ask1(double,double),
ask2(double,double);
int main(){
int lsy,c,n,m;
while(scanf("%d",&lsy)!=EOF){
while(lsy--){
scanf("%d%d%d",&c,&n,&m);
if(!c)fpen(ask1(n,m),9);
else fpen(ask2(n,m),9);putchar('\n');
}
}
return 0;
}
il void pen(int x){
if(x>9)pen(x/10);putchar(x%10+48);
}
il void fpen(double x,int n){
pen(x),x-=(int)x,putchar('.');
while(n--)
x*=10,putchar((int)x+48),x-=(int)x;
}
il double ask1(double n,double m){
return (pow(n,m)-1)/(n-1);
}
il double ask2(double n,double m){
double ans(1),opt(1);int i;
for(i=1;i<m;++i)
opt=opt*n/(n-i),ans+=opt;
return ans;
}
il double pow(double x,int y){
double ans(1);while(y){
if(y&1)ans*=x;
x*=x,y>>=1;
}return ans;
}