题意
求Ax≡B(mod P)Ax≡B(mod P)的最小非负整数解
BSGS裸题
自己推一下:
令x=im+jx=im+j ,m=⌈q√⌉m=⌈q⌉,
AimAj≡B(mod P)AimAj≡B(mod P)
Aj≡B∗inv(Aim)(mod P)Aj≡B∗inv(Aim)(mod P)
已知inv(1)=1inv(1)=1
由费马小定理得inv(Aim)=inv(A(i−1)m)∗Ap−1−m mod Pinv(Aim)=inv(A(i−1)m)∗Ap−1−m mod P(详细见代码后*)
那么inv就可以处理出来了。
把A0...mA0...mhash存一下
再求B∗inv(A(1...m)m)B∗inv(A(1...m)m)在hash表中查找。
#include <cstdio>
#include <map>
#include <iostream>
#include <cmath>
using namespace std;
typedef long long ll;
int p,b,n;
map<int,int> Mp;
inline int powf(ll x,int y,int p){
int k=1; x%=p;
while(y){
if(y&1) k=k*x%p;
x=x*x%p;
y>>=1;
}
return k;
}
inline void solve(int y,int z,int p){
y%=p;
if(!y&&!z) {puts("1");return;}
if(!y) {puts("no solution");return;}
ll t=ceil(sqrt(p)),k=1,ine=1;
Mp.clear(); Mp[1]=0;
for(int i=1;i<t;i++){
k=1ll*k*y%p;
if(Mp.count(k)) continue;
Mp[k]=i;
}
int tmp=powf(y,p-t-1,p);
for(int i=0;i<t;i++){
if(Mp.count(z*ine%p)) {printf("%d\n",i*t+Mp[z*ine%p]);return;}
ine=1ll*ine*tmp%p;
}
puts("no solution");
}
int main(){
while(~scanf("%d%d%d",&p,&b,&n)) solve(b,n,p);
}
*inv(Aim)=inv(A(i−1)m)∗Ap−1−mmodPinv(Aim)=inv(A(i−1)m)∗Ap−1−mmodP
proof.proof.
inv(A(i−1)m)=1Aim−minv(A(i−1)m)=1Aim−m
inv(A(i−1)m)∗Ap−1−m=Ap−1−mAim−minv(A(i−1)m)∗Ap−1−m=Ap−1−mAim−m上下同乘AmAm
Ap−1−mAim−m=Ap−1AimAp−1−mAim−m=Ap−1Aim
又因为费马小定理Ap−1≡1(modp)Ap−1≡1(modp)得
Ap−1Aimmodp=1Aimmodp=inv(Aim)Ap−1Aimmodp=1Aimmodp=inv(Aim)
所以inv(Aim)=inv(A(i−1)m)∗Ap−1−m mod Pinv(Aim)=inv(A(i−1)m)∗Ap−1−m mod P