2019牛客多校训练营第二场 A.Eddy Walker

题目链接

参考博客

题目描述

Eddy likes to walk around. Especially, he likes to walk in a loop called “Infinite loop”. But, actually, it is just a loop with finite
length(Anyway, the name doesn’t matter). Eddy can walk in a fixed length. He find that it takes him N N N steps to walk through the loop a cycle. Then, he puts N N N marks on the "Infinite loop"labeled with 0 , 1 , ⋯   , N − 1 0,1,\cdots,N−1 0,1,,N1, where i i i and i + 1 i+1 i+1 are a step away each other,so as 0 0 0 and N − 1 N-1 N1.After that,Eddy stands on the mark labeled 0 0 0 and start walking around. For each step, Eddy will independently uniformly randomly choose to move forward or backward. If currently Eddy is on the mark labeled i i i, he will on the mark labeled i + 1 i+1 i+1 if move forward or i − 1 i-1 i1 if move backward. If Eddy is on the mark labeled N − 1 N-1 N1 and moves forward, he will stand on the mark labeled 0 0 0. If Eddy is on the mark labeled 0 0 0 and moves backward, he will stand on the mark labeled N − 1 N-1 N1.

Although, Eddy likes to walk around. He will get bored after he reaches each mark at least once. After that, Eddy will pick up all the marks, go back to work and stop walking around.

You, somehow, notice the weird convention Eddy is doing. And, you record T T T scenarios that Eddy walks around. For i i i-th scenario, you record two numbers N i N_i Ni, M i M_i Mi, where N i N_i Ni tells that in the i i i-th scenario, Eddy can walk through the loop a cycle in exactly N i N_i Ni steps(Yes! Eddy can walk in different fixed length for different day.). While M i M_i Mi tells that you found that in the i i i-th scenario, after Eddy stands on the mark labeled M i M_i Mi, he reached all the marks.

However, when you review your records, you are not sure whether the data is correct or even possible. Thus, you want to know the probability that those scenarios will happen. Precisely, you are going to compute the probability that first i i i scenarios will happen sequentially for each i i i.

输入描述

The first line of input contains an integers T T T.

Following T T T lines each contains two space-separated integers N i N_i Ni

1 ≤ T ≤ 1021 1 \leq T \leq 1021 1T1021

1 ≤ M i < N i ≤ 1 0 9 1 \leq M_i <N_i \leq 10^9 1Mi<Ni109

输出描述

Output T T T lines each contains an integer representing the probability that first i i i scenarios will happen sequentially.

you should output the number module 1 0 9 + 7 ( 1000000007 ) 10^9+7(1000000007) 109+7(1000000007)

Suppose the probability is P Q \frac {P}{Q} QP,the desired output will be P × Q − 1 P\times Q^{-1} P×Q1 m o d mod mod 1 0 9 + 7 10^9 + 7 109+7

示例1
输入
3
1 0
2 1
3 0
输出
1
1
0

题目大意

总共有 T T T个回合,每个回合给你一个环,环的大小为 N N N,标记为 0 , 1 , ⋯ N − 1 0,1,\cdots {N-1} 0,1,N1,初始位置为 0 0 0,每次随机的向前或者向后走一步,每个点至少走一次,问满足第 i − 1 i-1 i1个回合的前提下,此回合每个点至少走一次,最后停在 M M M点的概率是多少。

解题思路

根据题意,模拟题目的过程进行打表,总结规律,发现

  • N = 1 N=1 N=1的时候,概率恒为1,

  • N ≥ 2 N\geq2 N2时,如果 m = 0 m=0 m=0,概率为 0 0 0,否则概率为 1 n − 1 \frac{1}{n-1} n11

题目要求求前 i i i个回合所有概率的乘积,同时用快速幂求乘法逆元,时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)

打表代码

#include
const int Max_N=1e6+10;
const int mod=1e9+7;
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
int moni(int n)
{
	int cnt=1,cur=0,vis[1000];
	memset(vis,0,sizeof(vis));
	vis[0]=1;
	while(cnt<n)
	{
		int pos=rand()%2;
		if(pos==0)
			cur=(cur-1+n)%n;
		else if(pos==1)
			cur=(cur+1)%n;
		if(!vis[cur])
		{
			vis[cur]=1;
			cnt++;
		}
	}
	return cur;
}
void solve(int n,int m)
{
	int cnt=0,ans=0;
	while(cnt<100005)
	{
		if(moni(n)==m)
			ans++;
		cnt++;
	}
	cout<<ans<<endl;
	cout<<cnt<<endl;
	cout<<ans*1.0/cnt<<endl;
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int n,m;
		cin>>n>>m;
		solve(n,m);	
	}
} 

AC代码

#include
const int Max_N=1e6+10;
const int mod=1e9+7;
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
ll pow_mod(ll a,ll b)
{
    ll res=1;
    while(b)
    {
        if(b&1)
            res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
int main()
{
    int t;
    cin>>t;
    ll res=1;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        if(n==1)
        {
            cout<<res<<endl;
            continue;
        }
        else if(m==0)
            res=0;
        else
        {
            res=res*pow_mod(n-1,mod-2)%mod;
        }
        cout<<res<<endl;
    }
}

总结

概率题目如果不能推算出结论,通过代码模拟题目过程,再总结规律也是一种较好办法。同时要仔细读题,题目要求算的是概率的前缀积,而不是某一次的概率。

你可能感兴趣的:(2019牛客多校训练营第二场 A.Eddy Walker)