BSGS 学习笔记
用于求 \(A^x \equiv B \pmod{C}\) 高次方程的最小正整数解 \(x\),其中 \(C\) 为素数
引理1,
\(p\)为素数,即 \(a^i\) 在模 \(p\) 的意义下会出现循环节 (注: \(\varphi(p)\) 可能不是最小循环节)
因为 \(a^{p-1}\equiv 1\pmod p\),则 \(a^{k\times(p-1)} \equiv 1 \pmod p\)
所以 \(a^{2k\times(p-1)}\times a^{-k*\times(p-1)} \equiv 1 \pmod p\)
即 \(a^{2k\times(p-1)}\) 为 \(a^{-k\times (p-1)}\) 模 \(p\) 意义下的逆元
$ \frac{a{i}}{a{k(p-1)}} \equiv a^{i}\times a^{2k\times (p-1)} \equiv a^{i}\times 1 \equiv a^{i} \pmod p$
即 \(a^{i-k(p-1)} \equiv a^{i} \pmod p\)
又因为 $i \bmod \varphi(p)=i-k\times (p-1) $
且 \(p\) 为素数,\(i-k\times (p-1)=i-k\times\varphi(p)\)
则 \(a^{i-k\times(p-1)} \equiv a^{i\mod\varphi(p)} \equiv a^{i} \pmod p\)
QED
根据引理1我们可知只需要枚举至多 \(\varphi(C)\) 个数就能知道方程的解,若枚举完后发现无解,则整个方程无解
考虑构造一个 \(m\),使得 \(m=\lceil\sqrt{C}\rceil\)
\(x=k\times m-q\),原方程转化为 \(A^{k\times m-q} \equiv B \pmod{p}\)
继而得到 $ A^{k\times m} \equiv B\times A^{q} \pmod{p}$
到了这一步,我们先考虑枚举 \(B*A^{q}\) 中的 \(q\),至多 \(\sqrt{C}\) 次,然后我们把得到的值存入一个Hash表中
接着我们开始枚举 $ A^{k\times m}$ 中的 \(m\),则两次枚举出来的式子的两两组合正好可以得到所有 $a \in [1,x] $,若遇到两次枚举出来的值相等,则输出答案,退出循环。
Code:
#include<stdio.h>
#include<math.h>
#include<map>
using namespace std;
#define ll long long
#define int ll
#define HASH_MOD 76799777LL
map<int,int> hash;
ll qpow(ll A,ll B,ll C){
if(B==0) return 1;
if(B==1) return A;
ll t=qpow(A,B>>1,C);
t=t*t%C;
if(B&1) t=t*A%C;
return t;
}
ll BSGS(ll A,ll B,ll C){
const int sizes=ceil(sqrt(C));
ll base=B%C;
hash[base]=0;
for(int i=1;i<=sizes;i++){
base=base*A%C;
hash[base]=i;
}
base=qpow(A,sizes,C);
ll tmp=1;
for(ll i=1;i<=sizes;i++){
tmp=tmp*base%C;
if(hash[tmp])
return ((i*sizes-hash[tmp])%C+C)%C;
}
return -1;
}
ll P,B,N;
signed main(){
scanf("%lld%lld%lld",&P,&B,&N);
if(!(B%P)){
printf("no solution\n");
return 0;
}
ll ans=BSGS(B,N,P);
if(ans!=-1) printf("%lld",ans);
else printf("no solution");
}