题目链接:https://ac.nowcoder.com/acm/contest/882/A
题意:现在有一个长度为未知环,每次你可以向前或者向后走一步。现在有T个回合,每个回合给你两个整数n和m。现在问你,在第i个回合中,在满足第i−1个回合的条件的前提下,在该回合中,将长度为n的环上的所有的点都访问过至少一次并最终落在点m的可能性。
解析:
对于这类询问概率的问题,我们可以采用蒙特卡洛随机的方法进行随机分析(说白了也就是随机算法)。
我们可以模拟若干次题意的操作,并求解出大概的概率,根据归纳分析,我们发现,当m不等于0的情况下,答案与m的值无关,只与n的值有关且答案为1/n−1。因此我们只需要用快速幂求解逆元即可,注意上一次回合的答案会累积到本回合。时间复杂度O(nlogn)。
需要注意的是,在swindows系统下,随机函数rand()rand()在数据较大的情况可能会发生比较大的误差。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
int montekalo(int n)
{
int cur=0,vis[10005],cnt=1;
memset(vis,0,sizeof(vis));
vis[0]=1;
int tmp=0;
while(cnt<n)
{
int x=rand()%szae;
if(x)
{
cur=(cur+1)%n;
}
else cur=(cur-1+n)%n;
if(!vis[cur])
{
vis[cur]=1;
cnt++;
}
}
return cur;
}
void gen(int n,int m)
{
int cnt=0,res=0;
while(cnt<=100000)
{
if(montekalo(n)==m) res++;
cnt++;
}
printf("%d %d %.5f\n",res,cnt,1.0*res/cnt);
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
gen(n,m);
}
return 0;
}