Label
简单BSGS+简单exgcd
Description
给定整数a,b,x1,t(0≤a,b,x1,t<p,2<p≤109,p为质数)a,b,x_1,t(0\leq a,b,x_1,t<p,2<p\leq10^9,p为质数)a,b,x1,t(0≤a,b,x1,t<p,2<p≤109,p为质数),每项取值范围为0∼p−10\sim p-10∼p−1的数列{x}\{x\}{x}满足:xi+1≡axi+b(modp)x_{i+1}\equiv ax_i+b(modp)xi+1≡axi+b(modp),试求最小的iii使得xi≡t(modp)x_i\equiv t(modp)xi≡t(modp),无解输出−1-1−1。每个数据点为多测(T≤50T\leq50T≤50)。
Solution
根据xxx的通项公式,利用迭代法我们可求得:
xn=an−1x1+b∑i=0n−2ai=an−1x1+b1−an−11−ax_n=a^{n-1}x_1+b\sum_{i=0}^{n-2}a^i=a^{n-1}x_1+b\frac{1-a^{n-1}}{1-a}xn=an−1x1+bi=0∑n−2ai=an−1x1+b1−a1−an−1
那么问题便可被转化为:求最小的nnn,使得
an−1x1+b1−an−11−a≡t(modp)a^{n-1}x_1+b\frac{1-a^{n-1}}{1-a}\equiv t(modp)an−1x1+b1−a1−an−1≡t(modp)
此为高次同余方程,经化简后,原式等价于
an−1≡t(a−1)+bx1(a−1)+b(modp)a^{n-1}\equiv \frac{t(a-1)+b}{x_1(a-1)+b}(modp)an−1≡x1(a−1)+bt(a−1)+b(modp)
令m=t(a−1)+bx1(a−1)+b=cdm=\frac{t(a-1)+b}{x_1(a-1)+b}=\frac{c}{d}m=x1(a−1)+bt(a−1)+b=dc由于ppp为质数,有:
1、我们可将同余号右端项换为其逆元,即令m=inv(m)=cdp−2m=inv(m)=cd^{p-2}m=inv(m)=cdp−2
2、此高次同余方程可利用普通的BSGSBSGSBSGS来解。
最后注意:
1、当a=0a=0a=0时特判;
2、a=1a=1a=1时,具体来讲,此时原方程等价于xn=x1+(n−1)b≡t(modp)x_n=x_1+(n-1)b\equiv t(mod p)xn=x1+(n−1)b≡t(modp),此为一阶线性同余方程,用exgcdexgcdexgcd解最小nnn即可。
Code
写题总结:
1、码力与程序流程、逻辑需要不断优化(比如下2);
2、多测时:所有的变量清空一定放到work函数的最前面;
3、考虑到且考虑清楚每一种特判的情况。
#include<cstdio>
#include<cmath>
#include<iostream>
#include<map>
#define ri register int
#define ll long long
using namespace std;
int Ttot;
ll B,X,T,aa,bb,xx,yy,xi,yi,g,a,b,p,t,ai=1,ans;
map<ll,int>hash;
ll Abs(ll x) {
return((x>0)?(x):(-x));
}
ll Gcd(ll x,ll y) {
return ((y==0)?(x):Gcd(y,x%y));
}
void exgcd(ll aa,ll bb)
{
if(bb==0)
{
xx=1; yy=0;
return;
}
exgcd(bb,aa%bb);
xi=xx,yi=yy;
xx=yi,yy=xi-(aa/bb)*yi;
}
ll power(ll x,ll y)
{
if(y==0) return 1%p;
if(y==1) return x%p;
ll now=power(x,y/2);
now=now*now%p;
if(y&1) now=now*x%p;
return now;
}
void BSGS()
{
t=sqrt(p);
if(t*t<p) ++t;
for(ll j=0;j<t;++j)
{
hash[b*ai%p]=j+1;
ai=ai*a%p;
}
a=power(a,t); ai=1;
for(ll i=0;i<=t;++i)
{
ll j=hash[ai];
if(j>=1)
{
ans=i*t-(j-1);
if(ans>0) return;
}
ai=ai*a%p;
}
}
void work()
{
ans=-1; hash.clear(); ai=1;
scanf("%lld%lld%lld%lld%lld",&p,&a,&B,&X,&T);
if(X==T) { cout<<"1"<<'\n'; return; }
if(a==0&&B==T) { cout<<"2"<<'\n'; return; }
if(a==0&&B!=T) { cout<<"-1"<<'\n'; return; }
if(a==1)
{
if(B==0) { cout<<"-1"<<'\n'; return; }
g=Gcd(B,p);
if((T-X)%g!=0) { cout<<"-1"<<'\n'; return; }
exgcd(B,p);
xx*=(T-X)/g;
xx=(xx%Abs(p/g)+Abs(p/g))%Abs(p/g);
cout<<xx+1<<'\n';
return;
}
b=(((T*(a-1)%p+B%p)%p)*power((X*(a-1)%p+B%p)%p,p-2))%p;
BSGS();
if(ans>=0) cout<<ans+1<<'\n';
else cout<<"-1"<<'\n';
}
int main()
{
scanf("%d",&Ttot);
for(ri i=1;i<=Ttot;++i) work();
return 0;
}