BSGS
\(BSGS(\)\(Baby\) \(Step\) \(Gaint\) \(Step)\),大步超大步小步算法,是求高次同余方程最小正整数解的一种常用算法。通常被用于求解形如使方程 \(a^x \equiv y (mod\) \(p)\) (\(p\) ⊥ \(a\) )成立的最小 \(x\)。
\(BSGS\) 算法的实现过程类似数学中的缩放法,将待求的指数 \(x\) 化为 \(a \sqrt p + b\),通过枚举 \(a\) 来求解。
具体过程如下:
一:
\(\large a^x \equiv y (mod\) \(\large p)\)
\(\large a^{ k\lceil \frac x k \rceil-(k\lceil \frac x k \rceil-x)}\equiv y (mod\) \(\large p)\) \(\large (k=\lceil \sqrt p \rceil)\)
\(\large {(a^k)}^n*a^{-m} \equiv y (mod\) \(\large p)\) \(\large (n=\lceil \frac x k \rceil,m=k\lceil \frac x k \rceil-x)\)
\(\large {(a^k)}^n \equiv inv_{(a^{-m})}*y=a^{m}*y\)
二:
设 \(\large k=\lceil \sqrt p \rceil\),\(x=n*k-m\),\(n\in [1,k)\),\(m\in [1,k)\)
则求 \(\large {(a^k)}^n \equiv inv_{(a^{-m})}*y=a^{m}*y\)
于是我们便可以从前往后枚举 \(m\) 以 \(y*(a^m)modp\) 为下标,\(m\) 为值存入一个 \(map\) 中(预处理),再枚举 \(n\) ,若存在 \(map[{(a^k)}^n]\),则 \(x=n*k-map[{(a^k)}^n]\).
复杂度 \(O(\sqrt p log p)\)
Code:
//P3846
#include<bits/stdc++.h>
using namespace std;
int p,x,y,k,n,a;
map<int,int>M;
int qp(int x,int y){
int s=1;
while(y){if(y&1)s=1ll*s*x%p;x=1ll*x*x%p;y>>=1;}
return s;
}
int main(){
cin>>p>>a>>y;
int k=ceil(sqrt(p));n=y;
for(int i=0;i<k;i++){ //预处理
M[n]=i;
n=1ll*n*a%p;
}
int t=qp(a,k);x=1;
for(int i=1;i<=k;i++){ //枚举答案
x=1ll*x*t%p;
if(M.count(x)){printf("%d\n",i*k-M[x]);return 0;}
}
puts("no solution");return 0;
}