BSGS算法(大小步算法)

$BSGS$ 算法 $Baby\ Steps\ Giant\ Steps$.

致力于解决给定两个互质的数 $a,\ p$ 求一个最小的非负整数 $x$ 使得 $a^x\equiv b(mod\ p)$ 其中 $b$ 为任意正整数,$2≤a<p$,$2≤b<p$

该算法使用的原理与欧拉定理有关,其中$a,\ p$互质

                  $a^{\phi (p)}\equiv 1(mod\ p)$

又因为

                  $a^0\equiv 1(mod\ p)$

所以$0到\phi p$是一个循环节,也就是说该算法最多查找$\phi (p)$次就可以找到答案,否则就无解。

设$x=im-k$其中$0≤k≤m$ 原式变为 

                  $a^{im-k}\equiv b(mod\ p)$

两边乘以$a^k$得到

                  $a^{im}\equiv a^kb(mod\ p)$

然后我们可以拆成左右两部分分别进行枚举$i$和$k$。

①先枚举$k$,把对应的结果$a^kb$和对应的$k$放入$map$中,$map\_name[a^kb]=k$。$(k\ from\ 0\ to\ m)$

②然后枚举$i$,把得到的结果$a^{im}$在$map$中进行查找,如果$map\_name.count(a^{im})$可以找到,则输出此时的$im-k$即可。($i\ from\ 1\ to\ m$)

如果超出查找范围还没找到,则无解。

这里注意下,对$a^{im}$枚举时,要先快速幂预处理出来$a^m$,然后枚举$i$即可。

算法时间复杂度为$O(max(m, \phi (p)/m))$.

最坏情况为$p$为质数$\phi (p)=p-1$

此时将$m$取$\sqrt p$为最小,时间复杂度为$O(\sqrt p)$。

$m$取$\sqrt p+1$或$ceil(\sqrt p)$。

例题:P3846 [TJOI2007]可爱的质数

代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

int n, p, b;

unordered_map<ll, int> vis;
inline ll fp( ll a, ll b ){
    a %= p;
    ll res = 1;
    while( b ){
        if( b&1 ) res = res*a%p;
        b >>= 1;
        a = a*a%p;
    }
    return res;
}

int main()
{

    ios::sync_with_stdio(0);

    cin.tie(0); cout.tie(0);
    cin >> p >> b >> n;
    ll m = ceil(sqrt(p));   /*算法复杂度O( max(m, phi(p)/m) ) 所以m取ceil(sqrt(p))最快O(sqrt(p)) */
    ll tmp = n;
    for( int k=0; k<=m; k++,(tmp*=b)%=p ){
        vis[tmp] = k;
    }
    ll t = fp(b, m); tmp = t;
    bool flag = 0;
    for( int i=1; i<=m; i++, tmp=tmp*t%p ){
        if( vis.count(tmp) ){
            flag = 1;
            cout << i*m-vis[tmp] << endl;
            break;

        }
    }
    if(!flag) cout << "no solution" <<endl;

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/WAautomaton/p/12048212.html