BSGS与ExBSGS:大步小步法

BSGS与ExBSGS:大步小步法

朴素BSGS

\(BSGS\)也就是\(Baby~ Step~ Giant~ Step\),用以解决形如以下的问题:

求解\(A^x \equiv B (mod~C)\)的最小整数解。其中\(A\)与\(C\)互质。

设\(x = am - b\)则原式变为
\[
A^{am-b}\equiv B(mod~C)
\]

\[
A^{am}\equiv B\times A^b(mod~C)
\]

然后我们假设\(m = \sqrt {C}\)则\(a \in [1, m], b \in [0, m)\),我们可以直接枚举\(b\)的可能取值然后对右边的式子进行计算,储存到\(map\)或者\(hash\)表里面(当然\(hash\)表相比起\(map\)是要更快的,因为\(map\)会带一个\(log\),但是博主懒~)。然后枚举所有可能的\(a\)然后查询右边的值有没有相等的值即可。

时间复杂度大概是\(O(\sqrt{C} logC)\)。给一个模板题的连接吧:Link

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>

using namespace std ;
typedef long long LL ;
const int MAXN = 100010, MAXM = 100010 ;
const int Inf = 0x7fffffff ;

int A, B, Mod, B2, T ; map <int, int> Map ;

inline int Read() {
    int X = 0, F = 1 ; char ch = getchar() ;
    while (ch > '9' || ch < '0') F = (ch == '-' ? - 1 : 1), ch = getchar() ;
    while (ch >= '0' && ch <= '9') X=(X<<1)+(X<<3)+(ch^48), ch = getchar() ;
    return X * F ;
}

inline int QuickPow(int X, int Y) {
    int Ans = 1 ; while (Y) {
        if (Y & 1) Ans = 1ll * Ans * X % Mod ;
        X = 1ll * X * X % Mod ; Y >>= 1 ;
    }   return Ans ;
}

int main() {
    Mod = Read() ; A = Read() ; B = Read() ;
    int M = sqrt(Mod) + 1 ; B2 = B ;
    for (int i = 0 ; i <= M ; i ++)
        Map[B2] = i, B2 = 1ll * B2 * A % Mod ;
    int T = QuickPow(A, M) ; B2 = 1 ;
    for (int i = 1 ; i <= M ; i ++) {
        B2 = 1ll * B2 * T % Mod ;
        if (Map.count(B2))
            return printf("%d\n", i * M - Map[B2]), 0 ;
    }
    printf("no solution\n") ;
    return 0 ;
}

ExBSGS扩展大步小步法

不用我说大家也知道有\(ExBSGS\)了,而多的条件就是\(A、C\)不一定互质了。我们这时无法进行朴素的\(BSGS\)的原因就在于之前的方法是基于欧拉定理的。
\[
A^{\varphi(C)} \equiv 1 (mod~C)
\]
可以看出最开始的方程的最小非负整数解一定在\([0, \varphi(C))\)中所以我们才能将枚举的范围缩小(因为循环节为\(\varphi(C)\)嘛。)但是欧拉定理使用的范围就是\(gcd(A, C) = 1\)。所以朴素的\(BSGS\)并不适用。这时应该怎么办呢?

既然\(gcd(A, C) ≠ 1\),那么我们就设\(D = gcd(A, C)\),然后改写原方程:
\[
A^x +kC = B
\]
这个方程有解当且仅当\(d|B\)时,所以我们可以约一下分。
\[
\frac {A \times A^{x - 1}}{D} + k \frac {C}{D} = \frac {B}{D}
\]
此时,如果\(gcd(A^{x - 1}, \frac {C}{D}) = 1\)我们就可以解下面这个方程:
\[
A^{X - 1} \equiv \frac {B}{D \frac {A} {D}}(mod ~ \frac{C}{D})
\]
不然的话我们就不断的持续上面的步骤,知道分解至\(gcd(A, C) = 1\)为止,我们就只需要解
\[
\frac{A^n \times A^{x - n}}{D} \equiv \frac{B}{D}(mod~\frac{C}{D})
\]
即可。最后我们还原BSGS的原来形式就可以了。这个模板洛谷好像还是有的:Link

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>

using namespace std ;
typedef long long LL ;
const int MAXN = 100010, MAXM = 100010 ;
const int Inf = 0x7fffffff ;

int A, B, Mod ; map <int, int> Map ;

inline int Read() {
    int X = 0, F = 1 ; char ch = getchar() ;
    while (ch > '9' || ch < '0') F = (ch == '-' ? - 1 : 1), ch = getchar() ;
    while (ch >= '0' && ch <= '9') X=(X<<1)+(X<<3)+(ch^48), ch = getchar() ;
    return X * F ;
}

inline int QuickPow(int X, int Y) {
    int Ans = 1 ; while (Y) {
        if (Y & 1) Ans = 1ll * Ans * X % Mod ;
        X = 1ll * X * X % Mod ; Y >>= 1 ;
    }   return Ans ;
}

inline int Gcd(int X, int Y) {
    if (! Y) return X ;
    return Gcd(Y, X % Y) ;
}

inline void ExBSGS(int A, int B) {
    if (B == 1)  {
        puts("0") ; return ;
    }
    int D = __gcd(A, Mod), K = 1, T = 0 ;
    while (D ^ 1) {
        if (B % D) {
            puts("No Solution") ; return ;
        }
        T ++ ; B /= D ; Mod /= D ; K = 1ll * K * (A / D) % Mod ;
        if (B == K) {
            printf("%d\n", T) ; return ;
        }
        D = __gcd(A, Mod) ;
    }
    int B2 = B ; Map.clear() ; int M = sqrt(Mod) + 1 ;
    for (int i = 0 ; i < M ; i ++)
        Map[B2] = i, B2 = 1ll * B2 * A % Mod ;
    B2 = K ; K = QuickPow(A, M) ;
    for (int i = 1 ; i <= M ; i ++) {
        B2 = 1ll * B2 * T % Mod ;
        if (Map.count(B2)) {
            printf("%d\n", i * M - Map[B2] + T) ; return ;
        }
    }   puts("No Solution") ;
}

int main() {
    while (1) {
        A = Read(), Mod = Read(), B = Read() ;
        if (! A && ! Mod && ! B) break ;
        A = A % Mod ; B = B % Mod ;
        ExBSGS(A, B) ;
    }
    return 0 ;
}

原文地址:https://www.cnblogs.com/Yeasio-Nein/p/BSGS.html

时间: 2024-10-12 03:27:53

BSGS与ExBSGS:大步小步法的相关文章

知识点简单总结——BSGS与EXBSGS

知识点简单总结--BSGS与EXBSGS BSGS 给出 $ A,B,C,(A,C)=1 $ ,要你求最小的 $ x $ ,使得 $ A^x \equiv B(mod \ C) $ . 在数论题中经常会看见这样的式子,而它的用处确实也不少,例如: 求指标 ...想不到了(被打) 解题思路 众所周知 $ A^{x} \equiv A^{x \ mod \ \phi (C) }(mod \ C) $ 所以考虑暴力枚举就可以. 但是我们显然要考虑一个更快的. 分块就好了. 设块大小 $ m $ ,预处

省选算法学习-BSGS与exBSGS

前置知识 扩展欧几里得,快速幂 都是很基础的东西 扩展欧几里得 说实话这个东西我学了好几遍都没有懂,最近终于搞明白,可以考场现推了,故放到这里来加深印象 翡蜀定理 方程$ax+by=gcd(a,b)$一定有整数解 证明: 因为$gcd(a,b)=gcd(b,a$ $mod$ $b)$ 所以假设我们已经求出来了$bx+(a$ $mod$ $b)y=gcd(b,a$ $mod$ $b)$的一组整数解$(p,q)$ 因为$a$ $mod$ $b=a-(\lfloor \frac{a}{b} \rflo

BSGS和EXBSGS

也许更好的阅读体验 \(Description\) 给定\(a,b,p\),求一个\(x\)使其满足\(a^x\equiv b\ \left(mod\ p\right)\) \(BSGS\) \(BSGS\)可以解决\(p\)为质数的情况 令 \(m=\lceil \sqrt p\rceil\) 令 \(x=i\cdot m-k\) 有 \(a^{i\cdot m-k} \equiv b\ (mod\ p)\) 两边同乘 \(a^k\) 得 \(a^{i\cdot m}\equiv b\cdot

BSGS 以及 ExBSGS

BSGS 引入 求解关于\(X\)的方程, \[A^X\equiv B \pmod P\] 其中\(Gcd(A,P)=1\) 求解 我们令\(X=i*\sqrt{P}-j\),其中\(0<=i,j<=\sqrt{P}\) 则原式可以变为: \[A^X\equiv B \pmod P\] \[A^{i*\sqrt{P}-j}\equiv B \pmod P\] 由于\(Gcd(A,P)=1\),则可以恒等变化为: \[A^{i*\sqrt{P}}\equiv B*A^j \pmod P\] 则我

BSGS算法学习

嗯哼大步小步法. 一个非常暴力的想法. 注意到如果设C = ⌈√P⌉,那么任何一个数都可以写 成a1 * C + b1的形式,其中a1, b1 都< C. 那么预处理出A^i*C的值.然后在询问时枚举b1. A^a1*C-b1 = B,A^a1*C = B * A^b1. 把A^b1乘一下,再去hash表里查找是否有对应的值即可. 复杂度为O(√P) //POJ 2417 1 #include<cstdlib> 2 #include<cstdio> 3 #include<

省选必知

简单列了一点 1.1 基本数据结构 1. 数组 2. 链表,双向链表 3. 队列,单调队列,双端队列 4. 栈,单调栈 1.2 中级数据结构 1. 堆 2. 并查集与带权并查集 3. hash 表 自然溢出 双hash 1.3 高级数据结构 1. 树状数组 2. 线段树,线段树合并 3. 平衡树 Treap 随机平衡二叉树 Splay 伸展树 * Scapegoat Tree 替罪羊树 4. 块状数组,块状链表 5.* 树套树 线段树套线段树 线段树套平衡树 * 平衡树套线段树 6.可并堆 左偏

待学习内容

太多了 近期: 分块 [高级数据结构] 4. 块状数组,块状链表 5.* 树套树 线段树套线段树 线段树套平衡树 * 平衡树套线段树 6.可并堆 左偏树 *配对堆 7. *KDtree,*四分树 [可持久化数据结构] 1. 可持久化线段树 @ 主席树 @ 2. * 可持久化平衡树 3. * 可持久化块状数组 [字符串相关算法及数据结构] 1. KMP @ 2. AC 自动机 3. 后缀数组 4. *后缀树 5. *后缀自动机 6. 字典树 Trie @ 7. manacher [图论] 1.K短

【学习整理】NOIP涉及的数论 [updating]

扩展欧几里得 求二元一次不定式方程 的一组解. int exgcd(int a,int b,int &x,int &y) { int t; if(!b) {x=1;y=0;return a;} t=exgcd(b,a%b,y,x); y-=(a/b)*x; return t; } 线性筛质数 维护一个质数表.对于每个数 , 从小到大枚举所有质数 ,将 打上标记. 如果 , 停止枚举. void getprime() { int i,j; for(i=2;i<=n;i++) { if(

数论...

果然还是太弱了啊.连着被ljj虐两天,暴力都一脸mengbi. 表示是时候好好整理一下数论了. 目录: NOIP难度: 1.gcd.lcm    2.埃氏筛法    3.exgcd,求解同余方程.逆元    4.快速幂    5.*组合数学    6.矩阵    7.欧拉函数    8.容斥原理    9.期望 省选难度: 1. (扩展)欧几里得算法,筛法,快速幂        斐蜀定理        更相减损术    2. 欧拉函数与*降幂大法    3. 费马小定理    4. 排列组合