2019牛客暑期多校训练营(第二场)A(随机化)
题意:
现在有一个长度为未知环,每次你可以向前或者向后走一步。现在有\(T\)个回合,每个回合给你两个整数\(n\)和\(m\)。现在问你,在第\(i\)个回合中,在满足第\(i-1\)个回合的条件的前提下,在该回合中,将长度为\(n\)的环上的所有的点都访问过至少一次并最终落在点\(m\)的可能性。
分析:
对于这类询问概率的问题,我们可以采用蒙特卡洛随机的方法进行随机分析(说白了也就是随机算法)。
我们可以模拟若干次题意的操作,并求解出大概的概率,根据归纳分析,我们发现,当\(m\)不等于\(0\)的情况下,答案与\(m\)的值无关,只与\(n\)的值有关且答案为\(\frac{1}{n-1}\)。因此我们只需要用快速幂求解逆元即可,注意上一次回合的答案会累积到本回合。时间复杂度\(\mathcal{O}(nlogn)\)。
需要注意的是,在\(\text{windows}\)系统下,随机函数\(\text{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()%2;
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);
}
const int mod=1e9+7;
ll powmod(ll x,ll n){
ll res=1;
while(n){
if(n&1) res=res*x%mod;
x=x*x%mod;
n>>=1;
}
return res%mod;
}
int main()
{
int t;
/*
while(~scanf("%d%d",&n,&m)){
gen(n,m);
}*/
scanf("%d",&t);
ll res=1;
while(t--){
ll n,m;
scanf("%lld%lld",&n,&m);
if(n==1){
printf("%lld\n",res);
continue;
}
else if(m==0) res=0;
else{
res=res*powmod(n-1,mod-2)%mod;
}
printf("%lld\n",res);
}
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步