题目大意
已知 a , b , p , x 1 , t a,b,p,x_1,t a,b,p,x1,t,生成一个序列 x i + 1 = ( a x i + b ) m o d p x_{i+1}= (ax_i+b)\bmod p xi+1=(axi+b)modp,问使 x i = t x_i=t xi=t 的最小 i i i 是多少。
题解
这个玩意看上去不太好做,我们考虑转换一下这个数列。
x
i
+
1
=
(
a
x
i
+
b
)
m
o
d
p
x
i
+
1
=
[
a
x
i
+
(
a
−
1
)
b
a
−
1
]
m
o
d
p
x
i
+
1
+
b
a
−
1
=
(
a
x
i
+
a
b
a
−
1
)
m
o
d
p
\begin{aligned} x_{i+1}&=(ax_i+b)\bmod p\\ x_{i+1}&=\left[ax_i+\dfrac{(a-1)b}{a-1}\right]\bmod p\\ x_{i+1}+\dfrac{b}{a-1}&=\left(ax_i+\dfrac{ab}{a-1}\right)\bmod p \end{aligned}
xi+1xi+1xi+1+a−1b=(axi+b)modp=[axi+a−1(a−1)b]modp=(axi+a−1ab)modp
发现左侧式子恰好是右侧式子的
a
a
a 倍。转换问题为:
(
t
+
b
a
−
1
)
×
inv
(
x
1
+
b
a
−
1
)
≡
a
n
−
1
(
m
o
d
p
)
\left(t+\dfrac{b}{a-1}\right)\times\operatorname{inv}\left(x_1+\dfrac{b}{a-1}\right)\equiv a^{n-1}\pmod p
(t+a−1b)×inv(x1+a−1b)≡an−1(modp)
这个式子可以直接用 BSGS 求解,这一题要注意特判 a = 0 or 1 a=0\;\text{or}\;1 a=0or1, x 1 = t x_1=t x1=t 的情况即可。时间复杂度 O ( p ) \mathcal{O}(\sqrt{p}) O(p)
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
char op=getchar();
int w=0,s=1;
while(op<'0'||op>'9'){
if(op=='-') s=-1;
op=getchar();
}
while(op>='0'&&op<='9'){
w=(w<<1)+(w<<3)+op-'0';
op=getchar();
}
return w*s;
}
int mod;
int Mul(int a,int b){return (a%mod*b%mod)%mod;}
int Add(int a,int b){return (a+b)%mod;}
int Dec(int a,int b){return (a-b+mod)%mod;}
int Pow(int a,int k){
int ans=1;
while(k){
if(k&1) ans=Mul(ans,a);
a=Mul(a,a);
k>>=1;
}
return ans;
}
int inv(int x){return Pow(x,mod-2);}
int BSGS(int a,int b,int p){
if(a%p==0) return -1;
unordered_map<int,int> mp;
int k=sqrt(p)+1;
for(register int i=0,cnt=b;i<=k;i++,cnt=Mul(cnt,a)) mp[cnt]=i;
int now=Pow(a,k);
for(register int i=1,cnt=1;i<=k;i++){
cnt=Mul(cnt,now);
if(mp.count(cnt)!=0) return i*k-mp[cnt]+1;
}
return -1;
}
signed main(){
int T=read();
while(T--){
int p=read(),a=read(),b=read(),x1=read(),xn=read();
mod=p;
if(x1==xn){
printf("1\n");
continue;
}
if(a==0){
if(xn==b) printf("2\n");
else printf("-1\n");
continue;
}
if(a==1&&b==0){
printf("-1\n");
continue;
}
if(a==1){
printf("%lld\n",Mul(Dec(xn,x1),inv(b))+1);
continue;
}
int t=Mul(b,inv(a-1));
printf("%lld\n",BSGS(a,Mul(Add(xn,t),inv(Add(x1,t))),p));
}
}