『笔记』BSGS
写在前面
开始之前先来两首 \(music\)
BSGS
简介
BSGS(baby-step giant-step),大步小步算法。
又被称为拔山盖世算法,又被称为北上广深算法。。。。
作用
求解满足
\[a^x \equiv b \pmod p \]的最小自然数 \(x\) 。
其中 \(a \perp p\) ,方程的解 \(x\) 满足 $ 0 \leq x < p$ 且数据范围较大,无法直接枚举在 \(O(p)\) 时间内通过。
令
其中
则有
由费马小定理得
我们已知 \(a,b\) 的取值,所以直接枚举 \(B\),计算 \(b \cdot a^B\) ,将其插入 \(hash\) 表,然后计算 \(a^{A\left \lceil \sqrt{p} \right \rceil}\),枚举所有 \(A\) 的值,看 \(hash\) 表中是否存在对应的 \(b \cdot a^B\),即可得到所有的解 \(x\)。
由于 \(A,B\) 均小于 \(\leq \left \lceil \sqrt{p} \right \rceil\) 所以总时间复杂度为 \(O(\sqrt{p})\),若使用 \(map\) 则多一个 \(\log\) 。
例题
T1
计算
\[a^x \equiv b \pmod p \]的最小非负整数解,无解时返回 \(-1\) 。
int BSGS(int a, int b, int p)
{
map<int, int> h;
h.clear();
b %= p;
int t = (int)sqrt(p) + 1;
for (int i = 1; i <= i; i++)
{
int tmp = (long long)b * Qpow(a, i, p) % p;
h[tmp] = i;
}
a = Qpow(a, t, p);
if (!a)
return !b ? 1 : -1;
for (int i = 0; i <= t; i++)
{
int tmp = Qpow(a, i, p);
if (h.find(tmp) == h.end())
return -1;
else if (i * t - h[tmp] >= 0)
return i * t - h[tmp];
}
return -1;
}
拓展 BSGS
简介
朴素的 \(BSGS\) 只有当 \(p\) 为质数是才可保证正确性,但是 \(OI\) 比赛中很多时候善良有爱的出题人并不想给出质数,那 \(BSGS\) 是否依旧可行呢?
自然,我们可以通过各种手段,使得 \(a \perp p\)。
前置芝士
若 \(a \equiv b(\bmod m)\) ,\(d\) 是 \(a, b\) 及 \(m\) 的任一正公因数,则有
若 \(a \equiv b(\bmod m), d \mid m, d>0\), 则 \(a \equiv b(\bmod d)\)。
若 \(a \equiv b(\bmod m)\), 则 $a k \equiv b k(\bmod m) $。
思路
求解满足
\[a^x \equiv b \pmod p \]的最小自然数 \(x\) 。
其中 \(p\) 不是质数。
设 \(d=\gcd(a,p)\),
若 \(d \nmid b\) 则 \(b=1\) 或 \(x=0\) 。否则,由裴蜀定理得,原方程无解。
不妨假设 \(d \mid b\),将原方程同时除以 \(d_1\) 得
此时对 \(a,p\) 再次进行判断,若 \(a\) 与 \(\cfrac{p}{d_1}\) 仍旧不互质,那么再除。
设 \(d_2=\gcd(a,\cfrac{p}{d_1})\),如果,\(d \nmid b_2\) 则原方程出现无解情况。否则对原方程同时除以 \(d_2\),得
同样执行上述判读和除法操作,直到 \(d=1\)。
此时有
设
则有
此时的 \(A\) 是与 \(P\) 互质的,便可以用朴素的 \(BSGS\) 求解了。
/*
Name: P4195 【模板】扩展BSGS
Solution: 扩展BSGS
By Frather_
*/
#include <iostream>
#include <map>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define int long long
#define InF 0x3f3f3f3f
#define kMax 10e5
#define kMin -10e5
#define kMod 998244353
using namespace std;
/*==================================================快读*/
inline int read()
{
int X = 0, F = 1;
char CH = getchar();
while (CH < '0' || CH > '9')
{
if (CH == '-')
F = -1;
CH = getchar();
}
while (CH >= '0' && CH <= '9')
{
X = (X << 3) + (X << 1) + (CH ^ 48);
CH = getchar();
}
return X * F;
}
/*===============================================定义变量*/
int a, p, b; //a^x=b (mod p)
/*=============================================自定义函数*/
int gcd(int a, int b)
{
return b ? gcd(b, a % b) : a;
}
int Qpow(int a, int p, int kmod)
{
int res = 1;
while (p)
{
if (p & 1)
res = res * a % kmod;
a = a * a % kmod;
p >>= 1;
}
return res;
}
// int BSGS(int a, int b, int p, int g)
// {
// map<int, int> hs;
// hs.clear();
// int t = (int)sqrt(p) + 1;
// for (int i = 0; i < t; i++)
// {
// int v = 1ll * b * Qpow(a, i, p) % p;
// hs[v] = i;
// }
// a = Qpow(a, t, p);
// if (!a)
// return !b ? 1 : -1;
// for (int i = 0; i <= t; i++)
// {
// int v = Qpow(a, i, p);
// // if (hs.find(v) != hs.end())
// // return -1;
// // if (hs[v] >= 0 && i * t - hs[v] >= 0)
// // return i * t - hs[v];
// int j = hs.find(v) == hs.end() ? -1 : hs[v];
// if (j >= 0 && i * t - j >= 0)
// return i * t - j;
// }
// return -1;
// }
int exgcd(int &x, int &y, int a, int b)
{
if (!b)
{
x = 1;
y = 0;
return a;
}
int t = exgcd(y, x, b, a % b);
y -= x * (a / b);
return t;
}
int BSGS(int a, int b, int p, int g)
{
map<int, int> hs;
hs.clear();
int t = ceil(sqrt(p));
int x, y;
exgcd(x, y, g, p);
b = (b * x % p + p) % p;
int q = Qpow(a, t, p);
exgcd(x, y, q, p);
q = (x * p + p) % p;
for (int i = 1, j = 0; j <= t; j++, i = i * a % p)
if (!hs.count(i))
hs[i] = j;
for (int i = b, j = 0; j <= t; j++, i = i * q % p)
if (hs[i])
return j * t + hs[i];
return -1;
}
int exBSGS(int a, int b, int p)
{
int res = 1;
int k=0, g=1;
if (b == 1)
return 0;
while ((g = gcd(a, p)) > 1)
{
if (b % g)
return -1;
k++;
b /= g;
p /= g;
res = res * (a / g) % p;
if (res == b)
return k;
}
return (g = BSGS(a, b, p, res)) == -1 ? -1 : g + k;
}
/*=================================================主函数*/
signed main()
{
while (true)
{
a = read();
p = read();
b = read();
if (!a && !p && !b)
return 0;
a %= p;
b %= p;
int ans = exBSGS(a, b, p);
if (ans < 0)
printf("No Solution\n");
else
printf("%d\n", ans);
}
return 0;
}
最后
掌握的不是很好哇,如果有错误欢迎向作者提出,蟹蟹!