原址:https://www.cnblogs.com/sdzwyq/p/9900650.html
BSGS
BSGS主要用于求解形如
x
k
=
y
(
m
o
d
p
)
x^k=y\pmod p
xk=y(modp)(注意这里p和x互质)这样的方程的最小正整数解得问题
设
m
=
⌈
p
⌉
,
k
=
a
m
−
b
,
a
∈
[
1
,
m
]
,
b
∈
[
0
,
m
)
m=\lceil\sqrt p\rceil,k=am-b,a\in[1,m],b\in[0,m)
m=⌈p⌉,k=am−b,a∈[1,m],b∈[0,m)那么上面的方程可以变形成
x
a
m
=
y
x
b
(
m
o
d
p
)
x^{am}=yx^b\pmod p
xam=yxb(modp)
枚举b,计算出右边的值存到map中,枚举a查表即可
Q:可以枚举左边存表,右边查嘛?
A:可以,但是左边查到表可以直接输出…
顺便一说,map里要存最大值,这样你算出的答案是最小的,所以能更新就更新
复杂度:
O
(
p
l
o
g
p
)
O(\sqrt plogp)
O(plogp)
模板题[TJOI2007]可爱的质数
#include <bits/stdc++.h>
using namespace std;
template <class T> void read(T &x) {
x = 0; bool f = 0; char ch = getchar();
while (!(ch >= '0' && ch <= '9')) {if (ch == '-') f = 1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
if (f) x = -x;
}
template <class T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x / 10) write(x / 10);
putchar('0' + x % 10);
}
int MOD;
int ksm(int a, int b) {int ret = 1; for (; b; b >>= 1, a = 1ll * a * a % MOD) if (b & 1) ret = 1ll * ret * a % MOD; return ret;}
map<int, int> mp;
int main() {
int x, y; read(MOD), read(x), read(y);
int m = sqrt(MOD) + 1, s = y;
for (int i = 0; i < m; i++) {mp[s] = i; s = 1ll * s * x % MOD;}
int t = ksm(x, m); s = 1;
for (int i = 1; i <= m; i++) {
s = 1ll * s * t % MOD;
if (mp[s]) {write(i * m - mp[s]); return 0;}
}
puts("no solution");
return 0;
}
扩展BSGS
当p不是素数时(这时x,p不一定互质),
设d=gcd(x,p),
若d不整除y,那么只有y=1时,x=0,其他情况均无解
若d整除y,当d=1时,直接BSGS
否则有
x
k
=
y
(
m
o
d
p
)
x^k=y\pmod p
xk=y(modp)
x
k
−
1
×
x
d
=
y
d
(
m
o
d
p
d
)
x^{k-1}×\frac{x}{d}=\frac{y}{d}\pmod{\frac{p}{d}}
xk−1×dx=dy(moddp)
继续分解到d=1为止.
x
k
−
t
×
x
t
∏
d
i
=
y
∏
d
i
(
m
o
d
p
∏
d
i
)
x^{k-t}×\frac{x^t}{\prod d_i}=\frac{y}{\prod d_i}\pmod{\frac{p}{\prod d_i}}
xk−t×∏dixt=∏diy(mod∏dip)
然后首先检验x=[0,t)是否为解,显然t是log级别的
如果[0,t)都不是解,由于x,
x
,
p
∏
d
i
x,\frac{p}{\prod d_i}
x,∏dip互质,BSGS求解即可
最后记得答案加上t,MOD一定要先除,map一定要用count查询元素
模板题[SPOJ3105]MOD
// luogu-judger-enable-o2
#include <bits/stdc++.h>
#define int long long
#define enter putchar('\n')
#define space putchar(' ')
using namespace std;
template <class T> void read(T &x) {
x = 0; bool f = 0; char ch = getchar();
while (!(ch >= '0' && ch <= '9')) {if (ch == '-') f = 1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
if (f) x = -x;
}
template <class T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x / 10) write(x / 10);
putchar('0' + x % 10);
}
int n, x, MOD, y;
map<int, int> mp;
inline void Mul(int &x, int y) {x = x * y % MOD;}
inline int ksm(int a, int b) {int ret = 1; for (; b; b >>= 1, Mul(a, a)) if (b & 1) Mul(ret, a); return ret;}
inline int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);}
inline void exbsgs(int x, int y) {
if (y == 1) {puts("0"); return;}
int d, k = 1, t = 0;
while ((d = gcd(x, MOD)) != 1) {
if (y % d) {puts("No Solution"); return;}
++t, y /= d, MOD /= d; Mul(k, x / d); //MOD一定要先除
if (k == y) {write(t); enter; return;}
}
int s = y, m = sqrt(MOD) + 1; mp.clear();
for (int i = 0; i < m; i++) mp[s] = i, Mul(s, x);
s = k, k = ksm(x, m);
for (int i = 1; i <= m; i++) {
Mul(s, k);
if (mp.count(s)) {write(i * m - mp[s] + t); enter; return;} //一定要用count
}
puts("No Solution");
}
inline int C(int n, int m) {
if (m > n) return 0;
int a = 1, b = 1;
for (int i = n - m + 1; i <= n; i++) Mul(a, i);
for (int i = 1; i <= m; i++) Mul(b, i);
return a * ksm(b, MOD - 2) % MOD;
}
inline int lucas(int n, int m) {
if (m == 0) return 1;
return (C(n % MOD, m % MOD) * lucas(n / MOD, m / MOD)) % MOD;
}
signed main() {
#if 0
read(n);
while (n--) {
int opt = 2;
//read(opt);
read(x), read(y), read(MOD);
if (opt == 1) write(ksm(x, y)), enter;
else if (opt == 2) exbsgs(x % MOD, y % MOD);
else write(lucas(y, x)), enter;
}
#endif
while (1) {
read(x), read(MOD), read(y);
if (!x && !y && !MOD) break;
exbsgs(x % MOD, y % MOD);
}
return 0;
}