zoukankan      html  css  js  c++  java
  • BSGS大步小步算法

    BSGS大步小步算法

    用于解决离散对数问题:

    已知 (a^x≡b (modquad p)),求 x 的最小非负整数解。其中 (gcd(a,p)=1)

    Small Step:对于 (i ϵ [0,S)) ,求出 (a^i% p=A[i])

    Big Step:对于 (j ϵ [0,p/S]) ,求出 (a^{jS}% p=B[j])

    这样如果 (A[i]×B[j] ≡ b) ( mod p) ,那么 (x=jS+i) 是合法解。

    也即若对于 (j ϵ [0,p/S]) ,若存在 (i ϵ [0,S)) ,使得(A[i]≡b×B[j]^{-1}) (mod p) ,那么 (x=jS+i) 是合法解。

    (S≈sqrt{p}),则时间复杂度为(O(sqrt{p} log⁡p))

    例1:New Product 板子,可爱的质数/【模板】BSGS

    [设u=sqrt(p), A^x≡B(modquad p)可转化为 A^{iu-j}≡B(modquad p),iϵ[1,u],jϵ[0,u)\ A^{iu}≡A^{j}B(modquad p)我们就可以枚举j,存到map中,再枚举i判重就行了\ 不过当存在不同的j使A^j≡b(modquad p)相同时,我们记录较大的(因为j越大答案越小嘛)\ 费马小定理:若gcd(x,p)=1,则有x^{p−1}≡1(modquad p),得到x^p≡x(modquad p)\ 所以当指数不小于p时,modquad p的值会形成循环\ 注意sqrt(p)必须上取整ceil()函数,否则sqrt(p)*sqrt(p)<p-1 漏了p-1这种情况 ]

    #include <cstdio>
    #include <iostream>
    #include <cmath>
    #include <map>
    using namespace std;
    #define int long long
    inline int read(){
        int x=0;char ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
        return x;
    }
    map<int,int>mp;
    int t,a,b,p;
    int qpow(int a,int b,int p){
        int ans=1;
        while(b){
            if(b&1) ans=(ans*a)%p;
            a=(a*a)%p;
            b>>=1;
        }
        return ans;
    }
    int BSGS(int a,int b,int p){
        if(!a)return b?-1:1;
        if(b==1)return 0;
        if(a%p==0) return -1;
        map<int,int>mp;
        int u=ceil(sqrt(p)),ax=b;
        for(int i=0;i<u;i++){
            mp[ax]=i;
            ax=ax*a%p;
        }
        int w=qpow(a,u,p),aj=1;
        for(int i=1;i<=u;i++){
    		aj=aj*w%p;
            if(mp.count(aj))return u*i-mp[aj];
        }
        return -1;
    }
    signed main(){
        t=read();
        while(t--){
            mp.clear();//清空好习惯
            p=read();a=read();b=read();
            int ans=BSGS(a,b,p);
            if(~ans) printf("%lld
    ",ans);
            else puts("Couldn't Produce!");
        }
        return 0;
    }
    
    

    例2:计算器

    #include <cstdio>
    #include <iostream>
    #include <cmath>
    #include <map>
    using namespace std;
    #define ll long long
    inline int read(){
        int x=0;char ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
        return x;
    }
    map<int,int>mp;
    int t,a,b,p,k;
    ll qpow(ll a,ll b,int p){
        ll ans=1;
        while(b){
            if(b&1) ans=(ans*a)%p;
            a=(a*a)%p;
            b>>=1;
        }
        return ans;
    }
    ll BSGS(ll a,ll b,ll p){
        if(!a)return b?-1:1;
        if(b==1)return 0;
        if(a%p==0) return -1;
        map<ll,ll>mp;
        ll u=ceil(sqrt(p)),ax=b;
        for(int i=0;i<u;i++){
            mp[ax]=i;
            ax=ax*a%p;
        }
        ll w=qpow(a,u,p),aj=1;
        for(int i=1;i<=u;i++){
    		aj=aj*w%p;
            if(mp.count(aj))return u*i-mp[aj];
        }
        return -1;
    }
    int main(){
        t=read();k=read();
        if(k==1){
            for(int i=1;i<=t;i++){
                a=read();b=read();p=read();
                printf("%lld
    ",qpow(a,b,p));
            }
        }else if(k==2){
            for(int i=1;i<=t;i++){
                a=read();b=read();p=read();
                if(a%p==0) printf("Orz, I cannot find x!
    ");
                else printf("%lld
    ",qpow(a,p-2,p)*b%p);
            }
        }else{
            for(int i=1;i<=t;i++){
                a=read();b=read();p=read();
                ll ans=BSGS(a%p,b%p,p);
                if(~ans) printf("%lld
    ",ans);
                else printf("Orz, I cannot find x!
    ");
            } 
        }
        return 0;
    }
    
    

    拓展BSGS

    [若gcd(a,p)≠1,令d=gcd(a,p),将方程改写成等式形式,a^x+kp=b;\ 此时 必须满足b|d,同时除以d 得到frac{a}{d}*a^{x-1}+frac{k}{d}*p=frac{b}{d}\ 这样前面的frac{a}{d}就是一个系数了,不断检查gcd(frac{b}{d},a),一直除到互质为止 此时的形式就变成了(frac{a}{d})^k*a^{x-k}≡frac{b}{d}(modquad frac{p}{d})\ 这样子bsgs求解之后在还原回去就行了。 ]

    好吧下面是正解,其实就多了这一步

    while(d!=1){
        if(b%d)return -1;
        p/=d;b/=d;++k;
        c=1ll*c*(a/d)%p;
        if(b==c) return k;
        d=gcd(a,p);
    }
    

    注意aj = c;

    还要特判 if(b==c) 的情况

    #include <cstdio>
    #include <iostream>
    #include <cmath>
    #include <map>
    using namespace std;
    #define int long long
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    map<int,int>mp;
    int t,a,b,p;
    int gcd(int a,int b){
        return b?gcd(b,a%b):a;
    }
    int qpow(int a,int b,int p){
        int ans=1;
        while(b){
            if(b&1) ans=(ans*a)%p;
            a=(a*a)%p;
            b>>=1;
        }
        return ans;
    }
    int ex_BSGS(int a,int b,int p){
        if(!a) return b?-1:1;
        if(b==1||p==1)return 0;
        if(a%p==0) return -1;
        int d=gcd(a,p),k=0,c=1;
        while(d!=1){
            if(b%d)return -1;
            p/=d;b/=d;++k;
            c=1ll*c*(a/d)%p;
            if(b==c) return k;
            d=gcd(a,p);
        }
        mp.clear();
        int u=ceil(sqrt(p)),ax=b;
        for(int i=0;i<u;i++){
            mp[ax]=i;
            ax=1ll*ax*a%p;
        }
        int w=qpow(a,u,p),aj=c;
        for(int i=1;i<=u;i++){
    		aj=1ll*aj*w%p;
            if(mp.count(aj)) return k+u*i-mp[aj];
        }
        return -1;
    }
    signed main(){
        while(1){
            a=read();p=read();b=read();
            if(!p && !a && !b) return 0;;
            int ans=ex_BSGS(a%p,b%p,p);
            if(~ans) printf("%lld
    ",ans);
            else puts("No Solution");        
        }
    }
    

    例3:多少个1?

    Desciption

    给定整数 K和质数 m,求最小的正整数 N,使得 11111⋯1(N个 1)≡K(mod m)

    Solution

    [N个1 可以转成等比数列求和 1,10,100....即 frac{10^n-1}{9}≡K(modquad m)\ 移项 10^n≡9*K+1(modquad m) ,令a=10,b=9*K+1,p=m,套exBSGS板子可过~~不去~~\ 额乘法爆long long,题解的巧妙方法,快速乘 ]

    #include <iostream>
    #include <cstdio>
    #include <map>
    #include <cmath>
    using namespace std;
    #define int long long 
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int mul(int a, int b, int P){//快速乘
        int L = a * (b >> 25ll) % P * (1ll << 25) % P;
        int R = a * (b & ((1ll << 25) - 1)) % P;
        return (L + R) % P;
    }
    int gcd(int a,int b){
        if(a<b) swap(a,b);
        return b?gcd(b,a%b):a;
    }
    int qpow(int a,int b,int p){
        int ans=1;
        while(b){if(b&1)ans=mul(ans,a,p);a=mul(a,a,p);b>>=1;}
        return ans;
    }
    map<int,int>mp;
    int ex_BSGS(int a,int b,int p){
        if(!a) return b?-1:1;
        if(b==1|p==1) return 0;
        if(a%p==0) return -1;
        int d=gcd(a,p),c=1,k=0;
        while(d!=1){
            if(b%d) return -1;
            b/=d;p/=d;++k;
            c=mul(c,a/d,p);
            if(b==c) return k;
            d=gcd(a,p);
        }
        mp.clear();
        int u=ceil(sqrt(p)),ax=b;
        for(int i=0;i<u;i++)
            mp[ax]=i,ax=mul(ax,a,p);   
        int aj=c,w=qpow(a,u,p);
        for(int i=1;i<=u;i++){
            aj=mul(aj,w,p);
            if(mp.count(aj)) return i*u-mp[aj]+k;
        }
        return -1;
    }
    signed main(){
        int k=read(),p=read();
        printf("%lld
    ",ex_BSGS(10,(9*k+1)%p,p));
    }
    
    
  • 相关阅读:
    WSP部署错误—SharePoint管理框架中的对象“SPSolutionLanguagePack Name=0”依赖其他不存在的对象
    Elevate Permissions To Modify User Profile
    Error with Stsadm CommandObject reference not set to an instance of an object
    ASP.NET MVC3添加Controller时没有Scaffolding options
    测试使用Windows Live Writer写日志
    配置TFS 2010出现错误—SQL Server 登录的安全标识符(SID)与某个指定的域或工作组帐户冲突
    使用ADO.NET DbContext Generator出现错误—Unable to locate file
    CSS
    HTML DIV标签
    数据库
  • 原文地址:https://www.cnblogs.com/ke-xin/p/13531944.html
Copyright © 2011-2022 走看看