BSGS及扩展BSGS总结(BSGS,map)

蒟蒻哪里有什么总结,只能点击%YL%

还有这位ZigZagK大佬的blog

BSGS

模板题:洛谷P3846 [TJOI2007]可爱的质数

给定a,b和模数YL,求axb(modYL)x的最小非负整数解。保证gcd(a,YL)=1

k=YL,令x=kycy[1,k],c[0,k),故分解唯一)

于是有akybac(modYL)

两边的取值都只有k种,枚举右边丢进map,再枚举左边查找一下即可得到最小的解。

复杂度O(YLlogYL)。注意特判掉一些特殊情况。

#include<bits/stdc++.h>
#define LL long long
#define RG register
#define R RG int
using namespace std;
map<int,int>c;
inline LL qpow(RG LL b,R k,RG LL YL){//快速幂
	RG LL a=1;
	for(;k;k>>=1,b=b*b%YL)
		if(k&1)a=a*b%YL;
	return a;
}
int main(){
	R a,b,YL;
	cin>>YL>>a>>b;
	if((b%=YL)==1)return puts("0"),0;//特判×2
	if((a%=YL)==0)return puts("no solution"),0;
	R k=sqrt(YL)+1,y;
	RG LL p,pw=qpow(a,k,YL);
	for(p=b,y=0;y<k;++y,(p*=a)%=YL)//预处理
		c[(int)p]=y;
	for(p=pw,y=1;y<=k;++y,(p*=pw)%=YL)//查找
		if(c.count((int)p))return(cout<<(LL)k*y-c[(int)p]<<endl),0;
	return puts("no solution"),0;//找不到
}

扩展BSGS

模板题:洛谷P4195 Spoj3105 Mod
双倍经验:洛谷SP3105 MOD - Power Modulo Inverted

可以解决gcd(a,YL)1的情况,核心思想是试探性地约去gcd

同余方程axb(modYL),可以提一个a出来改成不定方程aax1+YLy=b,等于说暂时把ax1看成了未知数。

g=gcd(a,YL),学完exgcd之后我们就知道了如果gb则方程组无解。否则就可以约成agax1+YLgy=bg

我们把约简后的方程看作一个新的不定方程aax1+YLy=b,如果gcd(a,YL)还是不为1的话,我们就再从幂里面拿出一个aYL约。如此循环。

终于在约了cnt次后,我们得到了一个gcd=1的方程了,变回来就是aaxcntb(modYL)

接下来的解法已经属于常规BSGS了,不过因为一些细节上的区别还是再写一遍。

仍然设k=YL,令x=kycy[1,k],c[0,k)

于是有aakybacntac(modYL),其实只是恒等号两边多乘了点东西而已。

约分多出来的复杂度是O(log2YL),因为最多被约log次,它的阶小于根号就忽略掉了。又要注意一些特判。

#include<bits/stdc++.h>
#define LL long long
#define RG register
#define R RG int
using namespace std;
map<int,int>c;
inline LL qpow(RG LL b,R k,RG LL YL){
    RG LL a=1;
    for(;k;k>>=1,b=b*b%YL)
        if(k&1)a=a*b%YL;
    return a;
}
int gcd(R x,R y){
    return y?gcd(y,x%y):x;
}
int main(){
    R a,b;RG LL YL;
    cin>>a>>YL>>b;
    while(a||b||YL){
        R x=-1,a1=1,cnt=0,g,k,y,p,pw;
        a%=YL;
        if((b%=YL)==1){x=0;goto L;}//这个特判上面提过
        while((g=gcd(a,YL))!=1){
            if(b%g)goto L;//无解充要条件
            ++cnt;b/=g;YL/=g;
            a1=a/g*(LL)a1%YL;
            if(a1==b){x=cnt;goto L;}
        }//注意这个特判,此时等价于a^{x-cnt}≡1(mod YL)
        c.clear();//多组数据注意清空
        k=sqrt(YL)+1;//常规BSGS过程
        pw=qpow(a,k,YL);
        p=b*qpow(a,cnt,YL)%YL;
        for(y=0;y<k;++y,p=(LL)p*a%YL)
            c[p]=y;
        p=(LL)a1*pw%YL;//多乘一个a1
        for(y=1;y<=k;++y,p=(LL)p*pw%YL)
            if(c.count(p)){x=k*y-c[p];break;}
      L:~x?printf("%d\n",x):puts("No Solution");
        cin>>a>>YL>>b;
    }
    return 0;
}
posted @   Flash_Hu  阅读(600)  评论(11编辑  收藏  举报
编辑推荐:
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
点击右上角即可分享
微信分享提示
哥伦布
-1°
10:09发布
哥伦布
10:09发布
-1°
西南风
2级
空气质量
相对湿度
87%
今天
小雨
-1°/13°
周六
多云
-3°/10°
周日
-4°/2°