「学习笔记」BSGS 算法
BSGS
求:满足一个最小的,满足:
其中 给定, 是质数
Solution
首先一个结论:我们取出 必然有一个
但是我们发现并不能这样,因为时间不允许,但可以进行如下操作
任意给个 求出来: 的值,放到一个 表中
然后我们再求:
对于每个 的次幂,我们移项,转化成下式:
然后我们把它扔到我们原来的 表里面找
如果找到了,答案就是
复杂度是显然的
实现用 std::map
实现会多 但是非常舒服
mp.clear(); int s=ceil(sqrt(p)),t=z%p; mp[t]=0;
for(int i=1;i<=s;++i) t=t*y%p,mp[t]=i;
int base=ksm(y,s,p),now=1; bool fl=0;
for(int i=1;i<=s;i++){
now*=base; now%=p;
if(!mp.count(now)) continue;
int t=i*s-mp[now];
printf("%lld\n",(t%p+p)%p); fl=1; break;
}
exBSGS
求:满足一个最小的,满足:
其中 给定,不保证模数为质数
Solution
可能在乘法的过程中把质因子凑全了,所以朴素的 BSGS 就施展不了拳脚了
特判 ,可以暴力:
枚举答案 同时在每一步除掉
如果什么时候 , 为最小解,同时如果 那么无解
对于 的情况
是任意的一个整数
由裴蜀定理:如果 无解
否则我们把等式两边 除 则有:
如果 不整除就继续除 ,整除之后就可以拿普通的 BSGS 做了
inline void work(){
y%=p; z%=p;
if(z==1) return puts("0"),void();
if(!y&&!z) return puts("1"),void();
if(!y) return puts("No Solution"),void();
if(!z){
int res=0,d;
while((d=__gcd(y,p))!=1){
++res; p/=d;
if(p==1) return printf("%lld\n",res),void();
}return puts("No Solution"),void();
}
int c=1,res=0,d;
while((d=__gcd(y,p))!=1){
if(z%d) return puts("No Solution"),void();
p/=d; z/=d; res++; (c*=y/d)%=p;
if(c==z) return printf("%lld\n",res),void();
}
mp.clear(); int t=z%p,s=ceil(sqrt(p)); mp[t]=0;
for(int i=1;i<=s;++i) (t*=y)%=p,mp[t]=i;
int base=ksm(y,s,p),now=c;
for(int i=1;i<=s;++i){
(now*=base)%=p;
if(!mp.count(now)) continue;
return printf("%lld\n",i*s+res-mp[now]),void();
} puts("No Solution");
return ;
}
广义BSGS
形式:
狭义的普通 BSGS 对应就是
如果我们把 看成矩阵什么的也一样能做
我们发现其实在 BSGS 中存在一部求逆函数的操作,其实就是逆元
然后我们对于要求的,找到相应的逆函数 (例如逆矩阵,向量的逆) 即可
应用是求广义斐波那契数列的循环节
例题:BZOJ 4128
矩阵求逆之后上 广义BSGS 即可,会被卡常
然而我们可以直接偷懒换式子:
所以我们把右边的所有结果存一存,左边就上矩阵乘就好了,并不用求逆
对于判定矩阵相等在哈希的射程范围之内
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律