BSGS & exBSGS

BSGS 

BSGS 用于当gcd(A,p)=1时,求方程的解。

由费马定理可知,当gcd(A,p)=1,且p为素数时,有所以得到

,x=am-b,,得到

通过枚举用hash维护任意一侧,再枚举另一侧,判断是否在hash,若在则答案为am-b。

例:poj 2417 Discrete Logging

#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
",i*m-lmapl[s]);
       f=1;
       break;
      }
    }
    if(!f) printf("no solution
");
  }
  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;
}
View Code

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;
}

例:poj 3243  Clever Y

#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
",ans);
    else printf("No Solution
");
  }
  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;
}
View Code
本博客仅为本人学习,总结,归纳,交流所用,若文章中存在错误或有不当之处,十分抱歉,劳烦指出,不胜感激!!!
原文地址:https://www.cnblogs.com/VividBinGo/p/11452707.html