51nod1836-战忽局的手段【期望dp,矩阵乘法】
正题
题目连接:http://www.51nod.com/Challenge/Problem.html#problemId=1836
题目大意
\(n\)个点\(m\)次随机选择一个点标记(可以重复),求最后被标记点的期望个数。
\(1\leq n,m\leq 10^{18}\)
解题思路
额开始拿方案数推了半天后面发现要斯特林数就放弃了,然后换了种方法发现很简单?
设\(i\)轮之后被标记点的期望个数是\(f_i\),那么有
\[f_i=f_{i-1}+\frac{n-f_{i-1}}{n}
\]
\[f_i=f_{i-1}\frac{n-1}{n}+1
\]
然后矩阵乘法就好了。
有一说一我第一次用期望值来算概率(((
时间复杂度\(O(T\log n)\)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int S=2;
struct Matrix{
__float128 a[S][S];
}f,ans,c;
long long T,n,m;
Matrix operator*(const Matrix &a,const Matrix &b){
c.a[0][0]=c.a[0][1]=c.a[1][0]=c.a[1][1]=0;
for(int i=0;i<S;i++)
for(int j=0;j<S;j++)
for(int k=0;k<S;k++)
c.a[i][j]+=a.a[i][k]*b.a[k][j];
return c;
}
int main()
{
scanf("%lld",&T);
while(T--){
scanf("%lld%lld",&n,&m);
f.a[1][1]=(__float128)(n-1)/n;
f.a[0][1]=f.a[0][0]=1;f.a[1][0]=0;
ans.a[0][0]=1;ans.a[0][1]=0;
while(m){
if(m&1)ans=ans*f;
f=f*f;m>>=1;
}
printf("%.12lf\n",(double)ans.a[0][1]);
}
return 0;
}