写在前面
开始之前先来两首 (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^{Aleft lceil sqrt{p} ight ceil}),枚举所有 (A) 的值,看 (hash) 表中是否存在对应的 (b cdot a^B),即可得到所有的解 (x)。
由于 (A,B) 均小于 (leq left lceil sqrt{p} ight ceil) 所以总时间复杂度为 (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(mod m)) ,(d) 是 (a, b) 及 (m) 的任一正公因数,则有
若 (a equiv b(mod m), d mid m, d>0), 则 (a equiv b(mod d))。
若 (a equiv b(mod m)), 则 $a k equiv b k(mod m) $。
思路
求解满足
[a^x equiv b pmod p ]的最小自然数 (x) 。
其中 (p) 不是质数。
设 (d=gcd(a,p)),
若 (d mid 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 mid 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
");
else
printf("%d
", ans);
}
return 0;
}
最后
掌握的不是很好哇,如果有错误欢迎向作者提出,蟹蟹!