浅谈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);
}
原文地址:https://www.cnblogs.com/gzezzry/p/12201829.html