题意
求 Ax≡B(mod P) A x ≡ B ( m o d P ) 的最小非负整数解
BSGS裸题
自己推一下:
令 x=im+j x = i m + j , m=⌈q√⌉ m = ⌈ q ⌉ ,
AimAj≡B(mod P) A i m A j ≡ B ( m o d P )
Aj≡B∗inv(Aim)(mod P) A j ≡ B ∗ i n v ( A i m ) ( m o d P )
已知 inv(1)=1 i n v ( 1 ) = 1
由费马小定理得 inv(Aim)=inv(A(i−1)m)∗Ap−1−m mod P i n v ( A i m ) = i n v ( A ( i − 1 ) m ) ∗ A p − 1 − m m o d P (详细见代码后*)
那么inv就可以处理出来了。
把 A0...m A 0... m hash存一下
再求 B∗inv(A(1...m)m) B ∗ i n v ( 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−mmodP i n v ( A i m ) = i n v ( A ( i − 1 ) m ) ∗ A p − 1 − m mod P
proof. p r o o f .
inv(A(i−1)m)=1Aim−m i n v ( A ( i − 1 ) m ) = 1 A i m − m
inv(A(i−1)m)∗Ap−1−m=Ap−1−mAim−m i n v ( A ( i − 1 ) m ) ∗ A p − 1 − m = A p − 1 − m A i m − m 上下同乘 Am A m
Ap−1−mAim−m=Ap−1Aim A p − 1 − m A i m − m = A p − 1 A i m
又因为费马小定理 Ap−1≡1(modp) A p − 1 ≡ 1 ( mod p ) 得
Ap−1Aimmodp=1Aimmodp=inv(Aim) A p − 1 A i m mod p = 1 A i m mod p = i n v ( A i m )
所以 inv(Aim)=inv(A(i−1)m)∗Ap−1−m mod P i n v ( A i m ) = i n v ( A ( i − 1 ) m ) ∗ A p − 1 − m m o d P