zoukankan      html  css  js  c++  java
  • 模板——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;
    }
    
  • 相关阅读:
    全字母短句
    java 遍历map的方法
    实现num1、num2交换,无中间变量
    N多条短信,用什么算法从中找出相似内容的来?
    Linux基础_磁盘分区
    Linux基础_软链接,硬链接
    Linux基础_系统启动流程
    Linux基础_合并,归档,压缩,dump,编辑器
    Linux基础_Linux操作系统简介
    计算机基础_操作系统
  • 原文地址:https://www.cnblogs.com/lajioj/p/9529255.html
Copyright © 2011-2022 走看看