模板——EXBSGS

(hash)版,省时间耗空间

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;

typedef long long LL;
const LL N=40000,Max=(1<<16)-1;
bool bk;
LL X,Z,K,len;
bool vis[70000];
struct node{
    LL d,id,next;
}hash[2*Max];

int exgcd(LL a,LL b,LL &x,LL &y)
{
    if(b==0) {x=1,y=0;return a;}
    LL tx,ty;
    LL d=exgcd(b,a%b,tx,ty);
    x=ty;y=tx-(a/b)*ty;
    return d;
}

void ins(LL d,LL id)
{
    LL t=d&Max;
    if(!vis[t]) {
        vis[t]=1;
        hash[t].d=d,hash[t].id=id,hash[t].next=-1;
        return ;
    }
    for(;hash[t].next!=-1;t=hash[t].next)
    {
        if(hash[t].d==d) return;
    }
    hash[t].next=++len;
    hash[len].d=d;hash[len].id=id;hash[len].next=-1;
}

LL find(LL d)
{
    LL t=d&Max;
    if(!vis[t]) return -1;
    for(;t!=-1;t=hash[t].next)
    {
        if(hash[t].d==d) return hash[t].id;
    }
    return -1;
}

LL BSGS()
{
    LL t,g,x,y,pm,a,b,c,m,k,sum,am;
    a=X;b=K;c=Z;k=1;sum=0;t=1%c;
    for(int i=0;i<=100;i++){
        if(t==b) return i;
        t=t*a%c;
    }
    while((g=exgcd(X,c,x,y))!=1)
    {
        k=(k*X/g)%c;
        c/=g;
        if(b%g) return -1;
        b/=g;
        sum++;
    }
    m=(LL)(ceil((double)sqrt((double)c)));
    ins(k,0);
    t=k;pm=1;
    for(int i=1;i<=m;i++)
    {
        t=t*a%c,pm=pm*a%c;
        ins(t,i);
    }        
    exgcd(pm,c,x,y);
    am=x%c+c;
    t=b;
    for(int i=0;i<=m;i++)
    {
        x=find(t);
        if(x!=-1) return i*m+x+sum;
        t=t*am%c;
    }
    return -1;
}

int main()
{
    while(~scanf("%lld%lld%lld",&Z,&X,&K)){
        K%=Z;len=Max;
        memset(vis,0,sizeof(vis));
        LL ans=BSGS();
        if(ans!=-1) printf("%lld
",ans);
        else printf("no solution!
");
    }
    return 0;
}

二分版,耗时间省空间

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;

typedef long long LL;
const int N=40000;
bool bk;
LL X,Z,K,a,b,c,m,k,sum,am,bl;
struct node{
    LL d,id;
}bit[N],p[N];

bool cmp(node x,node y){
    if(x.d!=y.d) return x.d<y.d;
    return x.id<y.id;
}

LL gcd(LL u,LL v)
{
    if(v==0) return u;
    return gcd(v,u%v);
}

LL find(LL x)
{
    int l=0,r=bl;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(bit[mid].d==x) return bit[mid].id;
        if(bit[mid].d>x) r=mid-1;
        if(bit[mid].d<x) l=mid+1;
    }
    return -1;
}

void exgcd(LL u,LL v,LL &x,LL &y)
{
    if(v==0) {x=1,y=0;return ;}
    LL tx,ty;
    exgcd(v,u%v,tx,ty);
    x=ty;y=tx-(u/v)*ty;
    return;
}

LL BSGS()
{
    LL t,g,x,y,pm;
    a=X;b=K;c=Z;k=1;sum=0;bk=1;bl=0;t=1%c;
    for(int i=0;i<=100;i++){//避免a的负数次方
        if(t==b) return i;
        t=t*a%c;
    }
    while((g=gcd(X,c))!=1)
    {
        k=(k*X/g)%c;//k记得要mod,否则溢出
        c/=g;
        if(b%g) return -1;
        b/=g;
        sum++;
    }
    m=(LL)(ceil((double)sqrt((double)c)));//要约分之后再求m
    p[0].d=k%c;
    p[0].id=0;
    pm=1;//pm是不用*k的
    for(int i=1;i<=m;i++) 
        p[i].d=p[i-1].d*a%c,pm=pm*a%c,p[i].id=i;
    sort(p,p+1+m,cmp);
    bit[0]=p[0];bl=0;
    for(int i=1;i<=m;i++)
    {
        if(p[i].d!=p[i-1].d) bit[++bl]=p[i];
    }
    exgcd(pm,c,x,y);
    am=(x%c+c);//避免am=0
    
    t=b;
    x=find(b);
    if(x!=-1) return x;
    for(int i=1;i<=bl;i++)
    {
        t*=am;t%=c;
        x=find(t);
        if(x!=-1)
            return i*m+x;
    }
    return -1;
}

int main()
{
//     freopen("exbsgs10.in","r",stdin);
//     freopen("exbsgs10.out","w",stdout);
    while(~scanf("%lld%lld%lld",&Z,&X,&K)){
        if(!X && !Z && !K) return 0;
        K%=Z;
        LL ans=BSGS();
        if(ans!=-1) printf("%lld
",ans+sum);
        else printf("no solution!
");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/lajioj/p/9529255.html