[学习笔记]BSGS
$\operatorname{BSGS}$ ,也即 $Baby\; step\; Giant\; step$ 大步小步算法,可以在 $\Theta(\sqrt{p})$ 的时间内求解
$$a^x\equiv b\pmod{p}$$
的问题,其中 $a,p$ 互质(也即 $a\perp p$)
那么首先显然地,$a^0\equiv 1\pmod{p}$;
又根据欧拉定理, $a^{φ(p)}\equiv 1\pmod{p}$
不难看出, $0\sim φ(p)$ 是一个循环节
也就是说,最多循环 $φ(p)$ 次就可以找到答案,否则无解
不妨设 $x=i\times m-k$,其中 $k\in [0,m]$
原方程变为 $a^{i\times m-k}\equiv b\pmod{p}$
移项,$a^{i\times m}\equiv a^kb\pmod{p}$
可以先计算 $a^kb\pmod{p}$ 的值,存入哈希表/ $\operatorname{map}$ 中
然后枚举可能的 $i$ 值,计算 $a^{i\times m}$ 的值进行查询
为什么要使用 $i\times m-k$ 而不是 $i\times m+k$ 呢?
事实上,两种方法都可行,但我们选择减法这是因为可以通过移项避免求逆元
也就是说,$\operatorname{BSGS}$ 算法共分为两步:
$\qquad\mathfrak{1:}$ $[0,m]$ 枚举 $k$,将 $a^kb\mod p$ 的值存入哈希表中
$\qquad\mathfrak{2:}$ $[1,\left \lceil \frac{p}{m} \right \rceil]$ 枚举 $i$,将 $a^{i\times m}\mod p$ 在表中进行查询,如果存在,此时的 $i\times m-k$ 即为答案
模板题目:TJOI2007可爱的质数
另外请特别注意,当 $a\mod p==0$ 且 $b\mod p \neq 0$ 时原方程无解(代码里好像没加)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstring> #include<string> #include<cmath> #include<map> #define WR WinterRain #define int long long using namespace std; const int WR=5010,INF=1099588621776; int BL,ans; map<int,int>mp; int read(){ int s=0,w=1; char ch=getchar(); while(ch>'9'||ch<'0'){ if(ch=='-') w=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=(s<<1)+(s<<3)+ch-48; ch=getchar(); } return s*w; } int quick_pow(int a,int b,int mod){ int base=a,res=1; while(b){ if(b&1) res=res*base%mod; base=base*base%mod; b>>=1; } return res; } void baby_step(int a,int b,int p){ int pw=0; while(pw<BL){ if(!mp[b]) mp[b]=pw+1; b=b*a%p,pw++; } } void giant_step(int a,int b,int p){ int pw=1,base,rec; base=rec=quick_pow(a,BL,p); while(pw<=BL){ if(mp[base]) ans=min(ans,BL*pw-mp[base]+1); base=base*rec%p,pw++; } } signed main(){ int p=read(),a=read(),b=read(); BL=ceil(sqrt(p));ans=INF; // printf("%lld\n",BL); baby_step(a,b,p); giant_step(a,b,p); if(ans==INF) printf("no solution\n"); else printf("%lld\n",ans); return 0; }
那么为什么不更进一步,考虑一下矩阵的 $\operatorname{BSGS}$ 呢?
显然对于矩阵,想做除法是需要求逆的,并不具备实际的可操作性
但是由于上面我们并没有用到除法(指数层面的减法避免了逆元),所以硬刚即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstring> #include<string> #include<cmath> #include<map> #define WR WinterRain #define int long long using namespace std; const int INF=1099588621776; const unsigned int hash1=345431,hash2=135757; int n,mod,BL; int ans=INF; struct Matrix{ int num[101][101]; unsigned int val1,val2; void clr(){memset(num,0,sizeof(num));val1=val2=0;} Matrix operator=(Matrix b){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ num[i][j]=b.num[i][j]; } } val1=b.val1,val2,b.val2; return *this; } Matrix operator*(const Matrix &b)const{ Matrix res;res.clr(); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ for(int k=1;k<=n;k++){ res.num[i][j]=(res.num[i][j]+num[i][k]*b.num[k][j]%mod)%mod; } } } return res; } Matrix operator*=(const Matrix &b){*this=*this*b;return *this;} void get_hash(){ val1=0,val2=0; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ val1=val1*hash1+(unsigned int)num[i][j]; val2=val2*hash2+(unsigned int)num[i][j]; } } } void print(){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ printf("%lld ",num[i][j]); } printf("\n"); } printf("%llu %llu\n",val1,val2); } }a,b; map<pair<unsigned int,unsigned int>,int>mp; int read(){ int s=0,w=1; char ch=getchar(); while(ch>'9'||ch<'0'){ if(ch=='-') w=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=(s<<1)+(s<<3)+ch-48; ch=getchar(); } return s*w; } Matrix quick_pow(Matrix a,int b,int mod){ Matrix base,res; base=a;res.clr(); for(int i=1;i<=n;i++) res.num[i][i]=1; while(b){ if(b&1) res*=base; base*=base; b>>=1; } return res; } void baby_step(Matrix a,Matrix b,int mod){ mp.clear();int pw=0; while(pw<BL){ b.get_hash(); // b.print(); if(!mp[make_pair(b.val1,b.val2)]) mp[make_pair(b.val1,b.val2)]=pw+1; b*=a;pw++; } } void giant_step(Matrix a,Matrix b,int mod){ ans=INF;int pw=1; Matrix base,rec; base=quick_pow(a,BL,mod);rec=base; base.get_hash(); while(pw<=BL){ base.get_hash(); // base.print(); if(mp[make_pair(base.val1,base.val2)]) ans=min(ans,pw*BL-mp[make_pair(base.val1,base.val2)]+1); base*=rec;pw++; } } signed main(){ n=read(),mod=read();BL=ceil(sqrt(mod)); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ a.num[i][j]=read(); } } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ b.num[i][j]=read(); } } a.get_hash(),b.get_hash(); baby_step(a,b,mod); giant_step(a,b,mod); printf("%lld\n",ans); return 0; }
本文来自博客园,作者:冬天丶的雨,转载请注明原文链接:https://www.cnblogs.com/WintersRain/p/16564635.html
为了一切不改变的理想,为了改变不理想的一切