(ex)BSGS/(扩展)大步小步算法 学习笔记

(ex)BSGS/(扩展)大步小步算法 学习笔记

在即将暂时退役之际杀掉了 P4195 的毒瘤模板题,于是来写篇学习笔记。

谨此为我初中三年摆烂的OI生涯画上一个句号。(距离中考还有20天!)

BSGS

link

axb(modp)非负整数解,其中a,p互质。

算法思路

我们不妨令 t=pj<tit

原式转化为 aitjb(modp)

(at)ibaj(modp)

于是我们可以这么在 Θ(n)(不考虑 hash 表)内求出解:

  • 枚举 j[0,t),求出所有的 bajmodp,用 hash 表记录下来

  • 枚举 i[0,t],求出所有的 (at)imodp,在 hash 表中查找是否有对应的 j

需要注意的是,当 atmodp=0 时,若 b=0,则解为 x=1
否则无解。

正确性讨论

由 Euler 定理,我们有 aφ(p)1(modp),其中 φ(x) 为 Euler 函数。

也就是说,modp 意义下,axmodpx=nφ(p)n 遍历非负整数)后循环。

我们知道对于任意整数 p>1p>φ(p),而我们取的 itj 可以遍历 [0,x],因此能够取到 apmodp 的一切情况,故一定不会漏解。

代码实现

#include <bits/stdc++.h>
using namespace std;
#define int long long
int qpow(int a, int n, int p) {
a%=p;
int res=1;
while (n) {
if (n&1) res=res*a%p;
a=a*a%p;
n>>=1;
}
return res;
}
signed bsgs(int a, int b, int p) {
b%=p;
int t=sqrt(p)+1;
unordered_map<int, int> hash; hash.clear();
for (int j=0; j<t; ++j) {
int power=b*qpow(a,j,p)%p;
hash[power]=j;
}
a=qpow(a,t,p);
if (a==0) return b==0?1:-1;
for (int i=0; i<=t; ++i) {
int val=qpow(a,i,p);
int j=hash.find(val)==hash.end()?-1:hash[val];
if (j>=0 && i*t-j>=0) return i*t-j;
}
return -1;
}
signed main() {
int a, b, p;
cin>>p>>a>>b;
int res=bsgs(a,b,p);
if (res==-1) puts("no solution");
else cout<<res<<endl;
return 0;
}

这份代码是可以通过 P3846 的。我们可以考虑对它进行优化。

我们发现枚举 aj(at)i 的时候,i,j 是递增的,于是我们可以直接用一个变量来维护 aj(at)i

另外,用 unordered_map 来实现 hash 表似乎会快一些。

inline int bsgs(int a, int b, int p) {
int t=(int)(sqrt(p))+1;
unordered_map<int,int> h; h.clear();
int powa=1;
for (reg int j=0; j<t; ++j) {
int val=powa*b%p;
h[val]=j;
powa=powa*a%p;
}
a=qpow(a,t,p);
powa=1;
for (reg int i=0; i<=t; ++i) {
int val=powa%p;
int j=h.find(val)==h.end()?-1:h[val];
if (j>=0 && i*t-j>=0) return i*t-j;
powa=powa*a%p;
}
return -1;
}

为exBSGS进行修改

我们现在来考虑 kaxb(modp)a,p 互质,k 为正整数)的式子,我们可以同样地将它们变形为

k(at)ibaj(modp)

于是稍微修改一下上述代码就可以了。

inline int bsgs(int a, int b, int k, int p) {
int t=(int)(sqrt(p))+1;
unordered_map<int,int> h; h.clear();
int powa=1;
for (reg int j=0; j<t; ++j) {
int val=powa*b%p;
h[val]=j;
powa=powa*a%p;
}
a=qpow(a,t,p);
powa=1;
for (reg int i=0; i<=t; ++i) {
int val=k*powa%p;
int j=h.find(val)==h.end()?-1:h[val];
if (j>=0 && i*t-j>=0) return i*t-j;
powa=powa*a%p;
}
return -1;
}

exBSGS

link

axb(modp)非负整数解,其中 a,p 未必互质

算法思路

考虑利用同余式的约化性质,转换成朴素的 BSGS 来求解。

我们有如下同余式的约化性质:
ab(modp)da,db,则

adbd(modpgcd(d,p))

我们回到 axb(modp),令 d1=gcd(a,p)
d1b,我们可以得到

ad1ax1bd1(modpd1)

(若 d1b,立刻得出无解)
a,pd1 仍不互质,我们可以继续令 d2=gcd(a,pd1),直到 a,pd1d2dk 互质为止。

我们设一共进行了 k 次约化,D=d1d2dk(此时 apD 互质),原式可变形为

akDaxkbD(modpD)

我们令 k=akD,X=xk,B=bD,P=pD,即

kaXB(modP)

于是可以利用修改后的BSGS算法来求解。

注意求解之后得到的 X=xk,故 x=X+k

Trick

akD=ad1ad2adk,于是可以在每一个循环内单独计算。

cout<<'\n' 似乎会比用 cout<<endl 快一些。

可以预先将 b%=p, a%=p,若取模过后 b=1p=1,那么显然 x=0 为解。

我们记 Dk=ad1ad2adk,当 akDk=bDk 时,有

akDkaxkbDk(modpDk)

axk1(modpDk)

于是 x=k 为解。其中 k 是正在进行的第 k 次约化。

代码实现

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define reg register
inline int qpow(int a, int n, int p) {
a%=p; int res=1;
while (n) {
if (n&1) res=res*a%p;
a=a*a%p; n>>=1;
}
return res;
}
inline int bsgs(int a, int b, int k, int p) {
int t=(int)(sqrt(p))+1;
unordered_map<int,int> h; h.clear();
int powa=1;
for (reg int j=0; j<t; ++j) {
int val=powa*b%p;
h[val]=j;
powa=powa*a%p;
}
a=qpow(a,t,p);
powa=1;
for (reg int i=0; i<=t; ++i) {
int val=k*powa%p;
int j=h.find(val)==h.end()?-1:h[val];
if (j>=0 && i*t-j>=0) return i*t-j;
powa=powa*a%p;
}
return -1;
}
inline int exbsgs(int a, int b, int p) {
a%=p, b%=p;
if (b==1 || p==1) return 0;
int A=a, NA=1, B=b, P=p, k=0, D=1;
while (__gcd(a,P)>1) {
int d=__gcd(a,P);
if (B%d) return -1;
k++; A/=d, B/=d, P/=d, NA=NA*(a/d)%P, D=D*d%P;
if (NA==B) return k; // NA就是上文提到的(a^k)/(D^k)
}
int res=bsgs(a,B,NA,P);
if (res==-1) return res;
if ((qpow(a,res+k,p)-b)%p) return -1;
return res+k;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
int a, b, p;
while (cin>>a>>p>>b && a) {
int res=exbsgs(a,b,p);
if (res==-1) cout<<"No Solution\n";
else cout<<res<<'\n';
}
return 0;
}

Record2.46s,可以通过本题(包括Hack数据)。

后记

这道题算是比较毒瘤的,我是一共调了三天才过的(我太弱了)
还有 20 天就要中考了,而我还在这摸鱼(悲)
就谨此纪念一下我的初中OI生涯罢。

顺便在此祝福向宴酱中考顺利!

本文作者:Starrykiller

本文链接:https://www.cnblogs.com/Starrykiller/p/bsgs_and_exbsgs.html

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

posted @   Starrykiller  阅读(95)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.