zoukankan      html  css  js  c++  java
  • 浅谈BSGS算法

    BSGS算法(Baby Step Giant Step)

    拔山盖世算法/北上广深算法

    先看一道同余题目:

    已知a,p互质,求解$a^xequiv bpmod p$

    我们该怎么做呢?

    设$m=ceil(sqrt{p})$,$x=i imes m-j$,$jin [0,m)$。(ceil为向上取整)

    所以$iin [0,m]$。

    对于所有$jin [0,m-1]$,把$b imes a^jpmod p$插入一个哈希表或map表中。(Baby Step)

    然后直接暴力枚举i,$iin [0,m]$,计算出$(a^m)^ipmod p$,在哈希表中查找是否存在对应的j,更新结果即可。(Giant Step)

    时间复杂度为$O(sqrt{p})$。

    代码

    # include<bits/stdc++.h>
    using namespace std;
    map<int,int>hash;
    int a,b,p,ans;
    int pow(int a,int b){
        int r=1;
        while(b){
            if(b%2)r=r*a%p;
            b/=2;
            a=a*a%p;;
        }
    }
    int bsgs(){
        int t,m=ceil(sqrt(p)),k=pow(a,p-m-1);
        hash[1]=m;
        for(int i=1;i<m;i++){
            t=(t*a)%p;
            if(!hash[t])hash[t]=i;
        } 
        for(int i=0;i<m;i++){
            if(hash[b]){
                int res=hash[b];
                hash.clear();
                if(res==m)return i*m;
                else return i*m+res;
            }
            b=(b*k)%p;
        }
        return -1;
    }
    int main(){
        scanf("%d%d%d",&a,&b,&p);
        ans=bsgs();
        if(ans==-1)printf("no solution
    ");
        else printf("%d",ans);
    }

    拓展BSGS算法

    回到上题,当a和p不互质时,又该怎么办呢?

    原方程等价于$a^x+py=b$

    令$g_1=gcd(a,p)$,此时b为$g_1$倍数时有整数解,否则无解。

    方程两边同时除以$g_1$可得:

    $frac{a}{g_1}a^{x-1}+frac{p}{g_1}y=frac{b}{g_1}$

    再令$g_2=gcd(frac{p}{g_1},a)$,若$g_2 e 1$,除以$g_2$可得:

    $frac{a^2}{g_1g_2}a^{x-2}+frac{p}{g_1g_2}y=frac{b}{g_1g_2}$

    不断检查$gcd(frac{p}{g_1g_2...g_i},a)$直到互质,则可写成:

    $frac{a……{cnt}}{g}a^{x-cnt}+frac{p}{g}y=frac{b}{g}$

    其中$g=g_1g_2...g_cnt$,cnt为检查的次数,此时$gcd(frac{p}{g},a)=1$

    上方程等价于$frac{a……{cnt}}{g}a^{x-cnt}equivfrac{b}{g}pmod{frac{p}{g}}$

    最后再用BSGS求出x-cnt即可。

    注意:这样只能得到大于cnt的解,可能会漏掉小于cnt的解,所以一般会先从1到50枚举一遍。

    #include<bits/stdc++.h>
    using namespace std;
    map<int,int>hash;
    int a,p,b,ans;
    int gcd(int a,int b){
        if(!b)return a;
        return gcd(b,a%b);
    }
    int pow(int a,int b){
        int r=1;
        while(b){
            if(b%2)r=r*a%p;
            b/=2;
            a=a*a%p;
        }
        return r;
    }
    int exbsgs(){
        a%=p,b%=p;
        if(b==1)return 0;
        int d=gcd(a,p),k=1,t=0;
        while(d^1){
            if(b%d)return -1;
            ++t,b/=d,p/=d,k=k*a/d%p;
            if(b==k)return t;
            d=gcd(a,p);
        }
        int s=b,m=ceil(sqrt(p));
        for(int i=0;i<m;i++){
            hash[s]=i;s=s*a%p;
        }
        s=k,k=pow(a,m);
        for(int i=1;i<=m;i++){
            s=s*k%p;
            if(hash[s])return i*m-hash[s]+t;
        }
        return -1;
    }
    int main(){
        scanf("%d%d%d",&a,&p,&b);
        ans=exbsgs();
        if(ans==-1)printf("no solution");
        else printf("%d",ans);
    }
  • 相关阅读:
    $.getJSON异步请求和同步请求
    Jquery中click事件重复执行的问题
    明白JavaScript原型链和JavaScrip继承
    利用canvas对上传图片进行上传前压缩
    webpack打包多html开发案例
    移动端的picker参考vux
    Vue于React特性简单对比(一)
    移动端调试和fiddler移动端抓包使用
    开发过程中的关键思维方法
    js移动端滑块验证解锁组件
  • 原文地址:https://www.cnblogs.com/gzezzry/p/12201829.html
Copyright © 2011-2022 走看看