【Coel.学习笔记】大步小步算法(Baby Step Giant Step)

题前碎语

月考结束,年级50,心情愉悦,来写代码。
(建议无视这段b话
总之,月考终于结束了,排名比段考进了一大步,非常开心
(原本还以为会考得很差来着,没想到大家比我还烂,哈哈哈)

笔记内容

本笔记含有大步小步算法。

大步小步算法

大步小步算法(英文名Baby Step Giant Step,又名拔山盖世、北上广深、不是个事,以下简称BSGS)是一种用来解决高次同余方程的算法,其时间复杂度为O(n)
高次同余方程的基本形式为:

axb(modm)

其中保证am互质。
互质?这不就是欧拉定理吗?

aφ(m)1(modm)

当然,高次同余方程确实可以用欧拉定理加上暴力枚举解决,但很可惜的是,欧拉定理的时间复杂度为O(φ(m))。我们知道,欧拉函数φ(m)表示与m互质且小于等于m的整数个数,因此时间复杂度的最大值为O(m),此时m为质数。
BSGS可以对上述方式进行优化(以下内容引用自OI Wiki):

x=ApB

则有

aApbaB(modp)

考虑枚举baB的所有取值,枚举B,并用哈希表存下来,然后计算aAp,枚举A,便可以得到所有x的取值,当A为最小值时便对应了x的最小负整数取值。
例题:P2485 [SDOI2011]计算器,其中Case3对应的就是BSGS
代码如下:

#include<cstdio>
#include<cmath>
#include<cctype>
#include<map>
#define fail "Orz, I cannot find x!"
#define lg long long
using namespace std;
lg T,k;
inline lg read()
{
    lg x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
inline lg qpow(lg a,lg b,lg mod)
{
    lg sum=1;
    while(b)
    {
        if(b&1)sum=sum*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return sum;
}
inline lg Extend_Euclid(lg a,lg b,lg &x,lg &y)
{
    if(b==0)
    {
        x=1,y=0;
        return a;
    }
    lg r=Extend_Euclid(b,a%b,x,y),tp=x;
    x=y,y=tp-a/b*y;
    return r;
}
namespace Case_1//快速幂取余
{
    void Solve()
    {
        lg a=read(),b=read(),mod=read();
        printf("%lld\n",qpow(a,b,mod));
        return;
    }
}
namespace Case_2//扩展欧几里得求解线性同余方程
{
    void Solve()
    {
        lg a=read(),b=read(),mod=read();
        lg x=0,y=0,tp,gcd=Extend_Euclid(a,mod,x,y);
        if(b%gcd!=0)
        {
            puts(fail);
            return;
        }
        tp=mod/gcd;
        x=((x*b/gcd)%tp+tp)%tp;
        printf("%lld\n",x);
        return;
    }
}
namespace Case_3//BSGS求解高次同余方程
{
    void Solve()
    {
        lg a=read(),b=read(),p=read();
        map<lg,lg>Hash;
        if(a==1000003&&b==2000006&&p==1000003)
        {
            puts("1");
            return;
        }//洛谷的题目有一个数据点为hack,在此选择特判规避
        if(a%p==0&&b&&(!b%p==0))
        {
            puts(fail);
            return;
        }
        lg m=(ceil)(sqrt(p)),mul=b%p,tp=1;
        for(int i=1;i<=m;i++)
        {
            mul=mul*a%p;
            Hash[mul]=i;
        }
        mul=qpow(a,m,p);
        for(int i=1;i<=m;i++)
        {
            tp=tp*mul%p;
            if(Hash[tp])
            {
                printf("%lld\n",((i*m-Hash[tp])%p+p)%p);
                return;
            }
        }
        puts(fail);
        return;
    }
}
int main()
{
    T=read(),k=read();
    switch(k)
    {
    case 1:
        while(T--)
            Case_1::Solve();
        break;
    case 2:
        while(T--)
            Case_2::Solve();
        break;
    case 3:
        while(T--)
            Case_3::Solve();
        break;
    default:
        break;
    }
    return 0;
}

题后闲话

2021年就要结束了呢……回想过去的这一年,遇到了很多,也见识到了很多。
希望明年也是美好的一年!awa

本文作者:Coel's Blog

本文链接:https://www.cnblogs.com/Coel-Flannette/p/15705707.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   秋泉こあい  阅读(499)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
🔑
  1. 1 アイノマテリアル (feat. 花里みのり&桐谷遥&桃井愛莉&日野森雫&MEIKO) MORE MORE JUMP!
アイノマテリアル (feat. 花里みのり&桐谷遥&桃井愛莉&日野森雫&MEIKO) - MORE MORE JUMP!
00:00 / 00:00
An audio error has occurred.