「学习笔记」BSGS 算法

BSGS

求:满足一个最小的x,满足:

AxBmod p

其中 A,B 给定,p 是质数

Solution

首先一个结论:我们取出A0Ap1 必然有一个 AqBmodp

但是我们发现并不能这样,因为时间不允许,但可以进行如下操作

任意给个 S 求出来:B×A1B×AS1mod p 的值,放到一个 hash 表中

然后我们再求:A0×SApS×S

对于每个 AS 的次幂,我们移项,转化成下式:

Ak×SB×Ap

然后我们把它扔到我们原来的 hash 表里面找

如果找到了,答案就是 k×Sp

复杂度是显然的 Θ(mod)

实现用 std::map 实现会多 log 但是非常舒服

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

求:满足一个最小的x,满足:

AxBmodp

其中 A,B 给定,不保证模数为质数

Solution

可能在乘法的过程中把质因子凑全了,所以朴素的 BSGS 就施展不了拳脚了

特判 B=0,可以暴力:

枚举答案 x 同时在每一步除掉 gcd(A,p)

如果什么时候 p=1x 为最小解,同时如果 gcd(A,p)=1 那么无解


对于 B0 的情况

Ax1×AB(mod p)

Ax1×Akp=B

k 是任意的一个整数

由裴蜀定理:如果 B0modgcd(A,p) 无解

否则我们把等式两边 除 gcd(A,p) 则有:

Agcd(A,p)×Ax1Bgcd(A,p)modpgcd(A,p)

如果 pgcd(A,p) 不整除就继续除 gcd,整除之后就可以拿普通的 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

形式:f(f(f(f(x))))=k(mod p)

狭义的普通 BSGS 对应就是 f(x)=x×A

如果我们把 f(x) 看成矩阵什么的也一样能做

我们发现其实在 BSGS 中存在一部求逆函数的操作,其实就是逆元

然后我们对于要求的f(x),找到相应的逆函数 (例如逆矩阵,向量的逆) 即可

应用是求广义斐波那契数列的循环节

例题:BZOJ 4128

矩阵求逆之后上 广义BSGS 即可,会被卡常

然而我们可以直接偷懒换式子:

AkS=B×At(mod p)

所以我们把右边的所有结果存一存,左边就上矩阵乘就好了,并不用求逆

对于判定矩阵相等在哈希的射程范围之内

posted @   没学完四大礼包不改名  阅读(252)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示