• [数论]原根与指标,BSGS


    刚学了这方面的知识,总结一下。推荐学习数论方面的知识还是看书学习,蒟蒻看的是《初等数论》学的。

    这里也推荐几个总结性质的博客,学习大佬的代码和习题。

    原根:https://blog.csdn.net/fuyukai/article/details/50894609

    BSGS:https://www.cnblogs.com/cjyyb/p/8810050.html

    https://blog.csdn.net/sodacoco/article/details/81515576

    然后也没什么好说的啦,以下是模板代码:

    求一个数的最小原根

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    LL prm[1000],tot,N,root;
    
    LL Power(LL x,LL p,LL MOD) {
        LL ret=1;
        for (;p;p>>=1) {
            if (p&1) ret=(ret*x)%MOD;
            x=(x*x)%MOD;
        }
        return ret;
    }
    
    LL GetRoot(LL n) {
        LL tmp=n-1,tot=0;
        for (LL i=2;i<=sqrt(tmp);i++) {
            if(tmp%i==0) {
                prm[++tot]=i;
                while(tmp%i==0) tmp/=i;
            }
        }
        if (tmp!=1) prm[++tot] = tmp;            //质因数分解
        for (LL g=2;g<=n-1;g++) {
            bool flag = 1;
            for(int i=1;i<=tot;i++)      //检测是否符合条件
                if(Power(g,(n-1)/prm[i],n)==1) { flag=0; break; } 
            if (flag)return g;
        }
        return 0;  //无解 
    }
    
    int main() {
        cin >> N;
        cout<<GetRoot(N)<<endl;
        return 0;
    }
    View Code

    普通BSGS:计算a^x≡b(mod p),要求a和p互质。

    #include<bits/stdc++.h>
    #define MOD 76543  //这是哈希表大小 
    using namespace std; 
    
    int hs[MOD],head[MOD],nxt[MOD],id[MOD],top;
    void insert(int x,int y) {
        int k=x%MOD;
        hs[top]= x,id[top]=y,nxt[top]=head[k],head[k]=top++;
    }
    
    int find(int x) {
        int k=x%MOD;
        for(int i=head[k];i!=-1;i=nxt[i])
            if(hs[i]==x) return id[i];
        return -1;
    }
    
    //普通BSGS:计算A^X=B(mod C)求X(A和C互质) 
    int BSGS(int a,int b,int c) {
        top=1; memset(head,-1,sizeof(head));  //清空哈希表 
        a%=c; b%=c;  //先取模 
        if(b==1) return 0;
        int m=sqrt(c*1.0),j;
        long long x=1,p=1;
        for(int i=0;i<m;++i,p=p*a%c)
            insert(p*b%c,i);//小步:存的是(a^j*b, j)
        for(long long i=m;;i+=m) {
            if((j=find(x=x*p%c))!=-1) return i-j;  //大步:a^(ms-j)=b(mod c)
            if(i>c) break;
        }
        return -1;  //无解 
    }
    
    int main()
    {
        int a,b,c; cin>>a>>b>>c;
        cout<<BSGS(a,b,c)<<endl;
        return 0;
    }
    View Code

    拓展BSGS,计算a^x≡b(mod p),但不要求a和p互质。代码学习yyb大佬的,测试:SPOJ-MOD 。

    #include<bits/stdc++.h>
    #define MOD 76543  //这是哈希表大小 
    using namespace std;
    typedef long long LL;
    
    LL power(LL x,LL p,LL mod) {
        LL ret=1;
        for (;p;p>>=1) {
            if (p&1) ret=(ret*x)%mod;
            x=(x*x)%mod;
        } 
        return ret;
    }
    
    int hs[MOD],head[MOD],nxt[MOD],id[MOD],top;
    void insert(int x,int y) {
        int k=x%MOD;
        hs[top]= x,id[top]=y,nxt[top]=head[k],head[k]=top++;
    }
    
    int find(int x) {
        int k=x%MOD;
        for(int i=head[k];i!=-1;i=nxt[i])
            if(hs[i]==x) return id[i];
        return -1;
    }
    
    //拓展BSGS:计算A^X=B(mod C)求X(不要求A,C互质) 
    int exBSGS(int y,int z,int p) {
        y%=p; z%=p;
        if (z==1) return 0;
        int k=0,a=1;
        while(1) {  //消因子 
            int d=__gcd(y,p); if(d==1)break;
            if(z%d) return -1;  //无解 
            z/=d; p/=d; ++k; a=1LL*a*y/d%p;
            if(z==a) return k;
        }
        top=1; memset(head,-1,sizeof(head));  //清空哈希表,BSGS 
        int m=sqrt(p)+1;
        for(int i=0,t=z;i<m;++i,t=1LL*t*y%p) insert(t,i);
        for(int i=1,tt=power(y,m,p),t=1LL*a*tt%p;i<=m;++i,t=1LL*t*tt%p) {
            int B=find(t); if(B==-1) continue;
            return i*m-B+k;
        }
        return -1;
    }
    
    int main()
    {
        int a,b,c;
        while (scanf("%d%d%d",&a,&c,&b)==3) {
            if (a==0 && b==0 && c==0) break;
            int t=exBSGS(a,b,c);
            if (t==-1) puts("No Solution"); else printf("%d
    ",t);
        }
        return 0;
    }
    View Code

    题目练习:

    洛谷P2485

    简单题,分别是求快速幂,逆元,BSGS。

    #include<bits/stdc++.h>
    #define MOD 76543  //这是哈希表大小 
    using namespace std;
    typedef long long LL;
    
    LL power(LL x,LL p,LL mod) {
        LL ret=1;
        for (;p;p>>=1) {
            if (p&1) ret=(ret*x)%mod;
            x=(x*x)%mod;
        } 
        return ret;
    }
    
    int hs[MOD],head[MOD],nxt[MOD],id[MOD],top;
    void insert(int x,int y) {
        int k=x%MOD;
        hs[top]= x,id[top]=y,nxt[top]=head[k],head[k]=top++;
    }
    
    int find(int x) {
        int k=x%MOD;
        for(int i=head[k];i!=-1;i=nxt[i])
            if(hs[i]==x) return id[i];
        return -1;
    }
    
    //普通BSGS:计算A^X=B(mod C)求X(A和C互质) 
    int BSGS(int a,int b,int c) {
        top=1; memset(head,-1,sizeof(head));  //清空哈希表 
        a%=c; b%=c;  //先取模 
        if(b==1) return 0;
        int m=sqrt(c*1.0),j;
        long long x=1,p=1;
        for(int i=0;i<m;++i,p=p*a%c)
            insert(p*b%c,i);//小步:存的是(a^j*b, j)
        for(long long i=m;;i+=m) {
            if((j=find(x=x*p%c))!=-1) return i-j;  //大步:a^(ms-j)=b(mod c)
            if(i>c) break;
        }
        return -1;  //无解 
    }
    
    int main()
    {
        int T,k; cin>>T>>k;
        while (T--) {
            int y,z,p; scanf("%d%d%d",&y,&z,&p);
            if (k==1) printf("%lld
    ",power(y,z,p));
            if (k==2) {
                if (y%p==0) puts("Orz, I cannot find x!");
                else printf("%lld
    ",z%p*power(y,p-2,p)%p);
            }
            if (k==3) {
                if (y%p==0) {puts("Orz, I cannot find x!"); continue;}
                int t=BSGS(y,z,p);
                if (t==-1) puts("Orz, I cannot find x!");
                else printf("%d
    ",t);
            }
        }
        return 0;
    }
    View Code

    洛谷P3306

    完全不会做qwq,蒟蒻只能自闭半天之后看题解,跟着大佬推。这道题很好,细节也很多,值得多思考。

    #include<bits/stdc++.h>
    #define MOD 76543  //这是哈希表大小 
    using namespace std; 
    typedef long long LL;
    
    LL power(LL x,LL p,LL mod) {
        LL ret=1;
        for (;p;p>>=1) {
            if (p&1) ret=(ret*x)%mod;
            x=(x*x)%mod;
        }
        return ret;
    }
    
    int hs[MOD],head[MOD],nxt[MOD],id[MOD],top;
    void insert(int x,int y) {
        int k=x%MOD;
        hs[top]= x,id[top]=y,nxt[top]=head[k],head[k]=top++;
    }
    
    int find(int x) {
        int k=x%MOD;
        for(int i=head[k];i!=-1;i=nxt[i])
            if(hs[i]==x) return id[i];
        return -1;
    }
    
    //普通BSGS:计算A^X=B(mod C)求X(A和C互质) 
    LL BSGS(int a,int b,int c) {
        top=1; memset(head,-1,sizeof(head));  //清空哈希表 
        a%=c; b%=c;  //先取模 
        if(b==1) return 0;
        int m=sqrt(c*1.0),j;
        long long x=1,p=1;
        for(int i=0;i<m;++i,p=p*a%c)
            insert(p*b%c,i);//小步:存的是(a^j*b, j)
        for(long long i=m;;i+=m) {
            if((j=find(x=x*p%c))!=-1) return i-j;  //大步:a^(ms-j)=b(mod c)
            if(i>c) break;
        }
        return -2;  //无解 
    }
    
    int main()
    {
        int T; cin>>T;
        LL p,a,b,x1,t;
        while (T--) {
            scanf("%lld%lld%lld%lld%lld",&p,&a,&b,&x1,&t);
            if (x1==t) { puts("1"); continue; }
            if (a==0) {
                if (b==t) puts("2"); else puts("-1");
                continue;
            }
            if (a==1) {
                if (b==0) puts("-1");
                else printf("%lld
    ",((t-x1)%p+p)%p*power(b,p-2,p)%p+1);
                continue;
            }
            int tmp=(t-t*a)%p; tmp=(tmp+p)%p;
            tmp-=b; tmp%=p; tmp=(tmp+p)%p;
            int ttmp=(x1-x1*a)%p; ttmp=(ttmp+p)%p;
            ttmp-=b; ttmp%=p; ttmp=(ttmp+p)%p;
            tmp=tmp*power(ttmp,p-2,p)%p;
            
            printf("%lld
    ",BSGS(a,tmp,p)+1);
        }
        return 0;
    }
    View Code

    BZOJ 1319

  • 相关阅读:
    多态
    课堂动手动脑
    凯撒加密
    构造方法、类初始化
    课堂动手动脑------随机数的产生
    课堂内容小结
    JAVA数字求和
    运行上次失败用例(--lf 和 --ff)
    conftest.py作用范围
    fixture作用范围
  • 原文地址:https://www.cnblogs.com/clno1/p/10918787.html
Copyright © 2020-2023  润新知