BSGS ! x

Posted 云深不知处

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BSGS ! x相关的知识,希望对你有一定的参考价值。

一.引入:

若存在一个式子a^b ≡ c (mod p) (p ≡ 1000000007,且0<a,b,c<p)

   已知a,b,求c.

     这不就是快速幂嘛!

  已知a,c,求b.

    这就是我们需要研究的问题!用到了BSGS!

题目链接:poj 2417 bsgs  

二.概念

BSGS:

又名大步小步算法.具体的我也不清楚啦~

那么发明来做什么事情呢?

如上所述:

  就是用来求解a^x ≡ b (mod p)这样的式子

    PS:已知a,b,p

        求最小x

三.做法

首先,我们将x用i*m-j来表示,其中我们的m=seil(sqrt(p)),(seil为向上取整)

然后我们用i*m-j代替掉x,所以原式就变成了这个样子

        a^(i * m-j) ≡ b (mod p)

又因为a^(i * m-j)  =>  a^(i * m)/a^j

所以原式又变了模样:

        a^(i * m)/a^j ≡ b (mod p)

又因为在"≡"(同余号)的两侧同时乘以一个相同的数依旧是成立的,如果不明白可以手动模拟一下,

给出个栗子~

  3 ≡ 10 (mod 7),当两边同乘以5时式子变成: 15 ≡ 50 (mod 7)

  因为15%7==1&&50%7==1,所以原式依旧成立

所以将式子两边同时乘以a^j

那么式子就又发生了改变:

        a^(i * m) ≡ b * a^j (mod p)

    = (a^m)^i ≡ b * a^j (mod p)

所以问题就简单多了!

因为a^m是常数,b是常数,p也是常数,所以只有 i 跟 j 是未知的,暴力枚举!

但是有一点是我们不能够忘记的:

m的取值范围:1 —— p(p是当b==0时),所以

首先将 j 从1 到 p-1 进行枚举一遍,求出b * a^j 的值丢到hash(大佬是用map做的)里面咯(讲真hash不会用...怪我咯?)

  思路是这样的:(其实就是hash啦~)

        (b*a^j)%p(如果p太小换成另外一个比较大的质数)作为下标,里面存着当前计算出来的数,以及当前的 j (可以用vector~) 

然后,枚举 j ,我们大可以设a^m==c

将 i 从 1 到p-1枚举一遍,如果求出的数在hash里面找到了,则说明当前的数就是 i (能够成立的) 最小值,跳出循环,用当前的i,以及记录下来的 j 计算对应的 i 求出 x 

则x就是最小的解

 

C++代码实现:

(map方法:)

技术分享
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#define LL long long 

using namespace std;

LL a,b,p;
map<LL,LL>mp;

LL fastpow(LL a,LL p,LL c)
{
    LL base=a;LL ans=1;

    while(c!=0)
    {
        if(c%2==1)ans=(ans*base)%p;
        base=(base*base)%p;
        c=c/2;
    }

    return ans;
}

int main()
{
    // a^x ≡ b (mod p)
    while(scanf("%lld%lld%lld",&p,&a,&b)!=EOF)
    {
        LL m=ceil(sqrt(p));// 这里必须要向上取整!!! 
        mp.clear();
        if(a%p==0)
        {
            printf("no solution\n");//(如果a)
            continue;
        }
        // 费马小定理的有解条件 
        LL ans;//储存每一次枚举的结果 b* a^j
        for(LL j=0;j<=m;j++)  // a^(i*m) = b * a^j
        {
            if(j==0)
            {
                ans=b%p;
                mp[ans]=j;// 处理 a^0 = 1 
                continue;
            }
            ans=(ans*a)%p;// a^j 
            mp[ans]=j;// 储存每一次枚举的结果 
        }
        LL t=fastpow(a,m,p);
        ans=1;//a ^(i*m)
        LL flag=0;
        for(LL i=1;i<=m;i++)
        {
            ans=(ans*t)%p;
            if(mp[ans])
            {
                LL ovo=i*m-mp[ans];// x= i*m-j
                printf("%lld\n",(ovo%p+p)%p);
                flag=1;
                break;
            }
            
        }
        if(!flag)
        printf("no solution\n");    
    }
    
    return 0;
}
ovo

 

End.

以上是关于BSGS ! x的主要内容,如果未能解决你的问题,请参考以下文章

扩展 BSGS

BSGS 算法

BSGS算法

BSGS模版 a^x=b ( mod c)

bsgs算法

BZOJ 3239 Discrete Logging(BSGS)