思路
假设目前我们所在的位置是 x x x,那么走一步之后的位置就是 x + x × m = x × ( m + 1 ) x+x\times m=x \times (m+1) x+x×m=x×(m+1),即每走一步我们所在的位置编号就会乘上 ( m + 1 ) (m+1) (m+1)。
于是题意被转化为求最小的正整数 a a a 使得 (m+1)\^a \\equiv 1 \\pmod{n} 。
由于 n n n 是质数,根据费马小定理, ( m + 1 ) n − 1 ≡ 1 ( m o d n ) (m+1)^{n-1} \equiv 1 \pmod{n} (m+1)n−1≡1(modn),于是有 a ∣ n − 1 a|n-1 a∣n−1。我们可以先对 n − 1 n-1 n−1 进行质因数分解,设 n o w now now 初始值为 n − 1 n-1 n−1,我们枚举每一个质因数 x x x,如果 (m+1)\^\\frac{now}{x} \\equiv 1 \\pmod{n} ,我们就令 n o w = n o w x now=\frac{now}{x} now=xnow,即试除,最后 n o w now now 的值就是答案。
这里有一个小技巧,直接分解质因数是时间复杂度 O ( n ) O(\sqrt n) O(n ) 的,但是由于这个题目中 n n n 比较小,我们可以先跑一遍线性筛求出每个数的最小质因子,这样复杂度就是 O ( log n ) O(\log n) O(logn) 的了。
代码
时间复杂度 O ( T n log 2 n ) O(Tn \log^2 n) O(Tnlog2n)(试除过程中需要用到快速幂)。
cpp
#include<bits/stdc++.h>
using namespace std;
int t,n,m,shai[10000005],u[10000005],cnt=0;
bool bj[10000005];
int ksm(int x,int y)
{
int now=x,op=1;
for(int i=0;(1<<i)<=y;i++)
{
if((1<<i)&y) op=1ll*op*now%n;
now=1ll*now*now%n;
}
return op;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
for(int i=2;i<=1e7;i++)
{
if(!bj[i]) u[++cnt]=i,shai[i]=1;
for(int j=1;j<=cnt&&u[j]*1ll*i<=1e7;j++)
{
bj[u[j]*i]=1,shai[u[j]*i]=u[j];
if(i%u[j]==0) break;
}
}
cin>>t;
while(t--)
{
cin>>n>>m;
if(m+1==n)
{
cout<<"2\n";
continue ;
}
int now=n-1;
vector<int> q;
while(now)
{
int y=shai[now];
if(y==1) break;
q.push_back(y),now/=y;
}
q.push_back(now),now=n-1;
for(int i=0;i<q.size();i++)
{
int u=now/q[i];
if(ksm(m+1,u)==1) now=u;
}
cout<<now<<"\n";
}
return 0;
}