题意:对于线性递推式\(X_{i+1}≡aX_i+b(\mod p)\),给定\(p,a,b,X_1,t\),求最小的\(i\)满足\(X_i=t\)或者判断无解.
分析:考虑对递推式子进行转化,
\(X_{i}=aX_{i-1}+b=a(X_{i-2}+b)+b\)
\(=...=a^{i-1}X_1+b+ab+a^2b+...+a^{i-2}b\)
\(=a^{i-1}X_1+\frac{b(a^{i-1}-1)}{a-1}=t\)
式子中只有\(a^{i-1}\)是未知量,而我们要求的就是\(i\),所以考虑把\(a^{i-1}\)单独拎出来,得到\(a^{i-1}≡\frac{(a-1)t+b}{(a-1)X_1+b}(\mod p)\)
所以就可以直接套BSGS了.但因为右边是个分式,所以需要特判几种情况.
1、若\(X_1=t\),分式的值为1,所以\(i=1\);
2、若\(a=0\),如果\(b=t\),分式的值为0,所以\(i=2\),否则无解,输出\(-1\);
3、若\(a=1\),如果\(b=0\),分式无解,输出\(-1\),否则有式子\(X_1+nb≡t(\mod p)\),直接求\(t-X_1\)乘b的逆元即可.
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
return s*w;
}
inline int ksm(int a,int b,int c){
int cnt=1;
while(b){
if(b&1)cnt=(1ll*cnt*a)%c;
a=(1ll*a*a)%c;
b>>=1;
}
return cnt;
}
map<int,int>ha;
inline int BSGS(int a,int b,int p){
if(a%p==0)return -2;
ha.clear();
int t=sqrt(p)+1,x=b,y=ksm(a,t,p);
for(int i=0;i<=t;i++){ha[x]=i;x=1ll*x*a%p;}
x=y;
for(int i=1;i<=t;i++){
if(ha.count(x))return i*t-ha[x];
x=1ll*x*y%p;
}
return -2;
}
int main(){
int T=read();
while(T--){
int p=read(),a=read(),b=read(),x1=read(),t=read();
if(x1==t){puts("1");continue;}
if(a==0){
if(b==t)puts("2");
else puts("-1");
continue;
}
if(a==1){
if(b==0)puts("-1");
else printf("%lld\n",1ll*ksm(b,p-2,p)*(t-x1+p)%p+1);
continue;
}
int c=1ll*b*ksm(a-1,p-2,p)%p;
int d=1ll*(t+c)*ksm(x1+c,p-2,p)%p;
printf("%d\n",BSGS(a,d,p)+1);
}
return 0;
}