BSGS & exBSGS
BSGS
BSGS 用于当gcd(A,p)=1时,求方程的解。
由费马定理可知,当gcd(A,p)=1,且p为素数时,有,所以得到。
令,x=am-b,,,得到,。
通过枚举用hash维护任意一侧,再枚举另一侧,判断是否在hash,若在则答案为am-b。
#include<iostream>
#include<cstdio>
#include<map>
#include<cmath>
using namespace std;
long long quick(long long a,long long b,long long p);
int main()
{
int i,f;
long long s,t,A,B,p,m;
while(~scanf("%lld%lld%lld",&p,&A,&B))
{
map<long long,long long> lmapl;
f=0;m=ceil(sqrt(p));
for(i=1;i<=m;i++)
{
B=B*A%p;
lmapl[B]=i;
}
t=quick(A,m,p);
for(i=1,s=1;i<=m;i++)
{
s=s*t%p;
if(lmapl[s])
{
printf("%lld\n",i*m-lmapl[s]);
f=1;
break;
}
}
if(!f) printf("no solution\n");
}
return 0;
}
long long quick(long long a,long long b,long long p)
{
long long ans=1;
while(b)
{
if(b&1) ans=ans*a%p;
b>>=1;
a=a*a%p;
}
return ans%p;
}
exBSGS
BSGS只能解决gcd(A,p)=1的情况,而通过exBSGS可以解决更一般的情况(不互质的情况)。
由,得到,令d=gcd(A,p),通过同余定理可以得到(如果B%d!=0,则无解),通过这种方式一直往下迭代,直到 d=1 ,此时得到。
令 ,k为迭代次数,得到,再通过BSGS求解,最后答案加上k。
int exbsgs(int a,int b,int p)
{
if (b==1||p==1)return 0; //特殊情况,x=0时最小解
int g=gcd(a,p),k=0,na=1;
while (g>1)
{
if (b%g!=0)return -1; //无法整除则无解
k++;b/=g;p/=g;na=na*(a/g)%p;
if (na==b)return k; //na=b说明前面的a的次数为0,只需要返回k
g=gcd(a,p);
}
int f=bsgs(a,b*inv(na,p)%p,p);
if (f==-1)return -1;
return f+k;
}
#include<iostream>
#include<cstdio>
#include<map>
#include<cmath>
#include<cstring>
using namespace std;
struct HashTable
{
static const int MOD=99901,MAXN=200005;
long long dat[MAXN],nxt[MAXN],head[MAXN],id[MAXN],cnt;
void clear()
{
memset(head,-1,sizeof(head));
memset(nxt,0,sizeof(nxt));
cnt=0;
}
void insert(long long x, long long y)
{
long long tmp=x%MOD;
for(int i=head[tmp];i!=-1;i=nxt[i])
if(dat[i]==x)
{
id[i]=y;
return;
}
dat[++cnt]=x;id[cnt]=y;
nxt[cnt]=head[tmp];head[tmp]=cnt;
}
long long query(long long x)
{
long long tmp=x%MOD;
for(int i=head[tmp];i!=-1;i=nxt[i])
{
if(dat[i]==x)
return id[i];
}
return -1;
}
}Hash;
long long quick(long long a,long long b,long long p);
long long bsgs(long long a,long long b,long long p,long long f);
long long exbsgs(long long a,long long b,long long p);
long long gcd(long long x,long long y);
int main()
{
long long a,p,b,ans;
while(scanf("%lld%lld%lld",&a,&p,&b))
{
if(!a&&!p&&!b) break;
ans=exbsgs(a,b,p);
if(ans!=-1) printf("%lld\n",ans);
else printf("No Solution\n");
}
return 0;
}
long long gcd(long long x,long long y)
{return y?gcd(y,x%y):x;}
long long quick(long long a,long long b,long long p)
{
long long ans=1;
while(b)
{
if(b&1) ans=ans*a%p;
b>>=1;
a=a*a%p;
}
return ans;
}
long long exbsgs(long long a,long long b,long long p)
{
Hash.clear();
if(b==1||p==1) return 0;
long long d=gcd(a,p),k=0,na=1,ans;
while(d!=1)
{
if(b%d) return -1;
k++;b/=d;p/=d;na=na*(a/d)%p;
if(na==b) return k;
d=gcd(a,p);
}
ans=bsgs(a,b,p,na);
return ans==-1?-1:ans+k;
}
long long bsgs(long long a,long long b,long long p,long long f)
{
int i;
long long m=ceil(sqrt(p)),s,t;
for(i=1;i<=m;i++)
{
b=b*a%p;
Hash.insert(b, i);
}
t=quick(a,m,p);
for(i=1,s=f;i<=m;i++)
{
s=s*t%p;
if(Hash.query(s)!=-1) return i*m-Hash.query(s);
}
return -1;
}