(ex)BSGS/(扩展)大步小步算法 学习笔记
(ex)BSGS/(扩展)大步小步算法 学习笔记
在即将暂时退役之际杀掉了 P4195 的毒瘤模板题,于是来写篇学习笔记。
谨此为我初中三年摆烂的OI生涯画上一个句号。(距离中考还有20天!)
BSGS
求
算法思路
我们不妨令
原式转化为
即
于是我们可以这么在
-
枚举
,求出所有的 ,用 hash 表记录下来 -
枚举
,求出所有的 ,在 hash 表中查找是否有对应的 值
需要注意的是,当
否则无解。
正确性讨论
由 Euler 定理,我们有
也就是说,
我们知道对于任意整数
代码实现
#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 的。我们可以考虑对它进行优化。
我们发现枚举
另外,用 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进行修改
我们现在来考虑
于是稍微修改一下上述代码就可以了。
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
求
算法思路
考虑利用同余式的约化性质,转换成朴素的 BSGS 来求解。
我们有如下同余式的约化性质:
若
我们回到
当
(若
若
我们设一共进行了
我们令
于是可以利用修改后的BSGS
算法来求解。
注意求解之后得到的
Trick
用 cout<<'\n'
似乎会比用 cout<<endl
快一些。
可以预先将 b%=p, a%=p
,若取模过后
我们记
即
于是
代码实现
#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; }
Record,
后记
这道题算是比较毒瘤的,我是一共调了三天才过的(我太弱了)
还有
就谨此纪念一下我的初中OI生涯罢。
顺便在此祝福向宴酱中考顺利!
本文作者:Starrykiller
本文链接:https://www.cnblogs.com/Starrykiller/p/bsgs_and_exbsgs.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】