BSGS(大小步)算法

BSGS算法主要用于求解形如ax≡b(mod p)的式子中x的值。

在这里我们不妨设

     x=k1*n-k2

这时我们就可以将式子转化为

     ak1*n≡b*ak2(mod p)

这里的n我们设为√p,所以我们利用分块的思想在块数范围内枚举k1即可。那在考虑完k1和n之后我们再考虑一下如何找到k2,我们建立一个哈希表,将k2取0~n时的式子左边的值模p然后将其映射到此时k2的取值。求最后答案时我们只需找到在k1最小时满足条件的最大的k2即可。

更新

发现以前有点问题

根据欧拉定理$a^{varphi(p)} equiv 1(mod p)$

所以代码里所有的$p$都替换成$varphi(p)$即可

块的大小也为$sqrt{varphi(p)}$

模板(poj2417

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
map<long long,long long>mp;
inline long long pw(long long a,long long p,long long mod){
    long long res=1;
    while(p){
        if(p&1)res=res*a%mod;
        a=a*a%mod;
        p>>=1;
    }
    return res;
}
int main(){
    long long a,b,p,m,n,i,j,k,pl;
    while(scanf("%lld%lld%lld",&p,&a,&b)!=EOF){
        n=ceil(sqrt(p));
        mp.clear();
        long long x=b%p;
        mp[x]=0;
        for(i=1;i<=n;i++){
            x=x*a%p;
            mp[x]=i;
        }
        long long y=pw(a,n,p),ok=0;
        x=1;
        for(i=1;i<=n;i++){
           x=x*y%p;
           if(mp[x]){
                ok=1;
                pl=i;
                break;
           }
        }
        if(ok){
            printf("%lld
",((pl*n%p-mp[x])%p+p)%p);
        }else puts("no solution");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/yzxverygood/p/9160401.html