离散对数问题
给出 a , b , p a,b,p a,b,p,求解 a x = b ( m o d n ) a^x=b\ (mod\ \ n) ax=b (mod n)
Baby-Step Giant-Step
简称BSGS算法,(也叫北上广深算法)。复杂度
O
(
n
)
O(\sqrt{n})
O(n),
n
n
n是不是质数都可以。核心是利用较普通查询方式速度更快的Hash表查询。
设
m
=
n
m=\sqrt{n}
m=n
那么令
x
=
k
⋅
m
−
t
x=k·m-t
x=k⋅m−t
所以原式等价
a
k
⋅
m
−
t
=
b
(
m
o
d
n
)
a^{k·m-t}=b\ (mod\ \ n)
ak⋅m−t=b (mod n)
即
(1)
(
a
m
)
k
=
b
⋅
a
t
(
m
o
d
n
)
(a^m)^k=b·a^t\ (mod\ \ n)\tag{1}
(am)k=b⋅at (mod n)(1)
然后从
0
−
m
0-m
0−m枚举
t
t
t,将
b
⋅
a
t
b·a^t
b⋅at存入Hash表
从
m
m
m开始枚举
m
⋅
k
m·k
m⋅k,每次加
m
m
m,其实就是相当于从1开始枚举
k
k
k,从Hash表中找到第一个满足式
(
1
)
(1)
(1)的解。
此时
x
=
m
⋅
k
−
t
x=m·k-t
x=m⋅k−t
我自己的模板
//BSGS
int BSGS(int a,int b,int n){ //a^x = b (mod p)
map<ll,ll> mp;
if(b == 1) return 0;
int m = sqrt(1.0*n);
ll x = 1,p = 1;
b %= n;
for(int i = 0; i < m; ++i, p = p*a%n) mp[p*b%n]=i;
for(ll i = m ;; i += m){
if(mp.count(x = x*p%n)) return i-mp[x];
if(i > n) break;
}
return -1;
}
//exBSGS
// #include <bits/stdc++.h>
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
#include <unordered_map>
#include <set>
#include <vector>
#include <assert.h>
#include <cmath>
#include <ctime>
using namespace std;
#define me(x,y) memset((x),(y),sizeof (x))
#define MIN(x,y) ((x) < (y) ? (x) : (y))
#define MAX(x,y) ((x) > (y) ? (x) : (y))
#define SGN(x) ((x)>0?1:((x)<0?-1:0))
#define ABS(x) ((x)>0?(x):-(x))
// #define int __int128
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const ll maxn = 2e5+10;
const double INF = 0x3f3f3f3f;
const int MOD = 1e9+7;
const double eps = 1e-17;
const double PI = std::acos(-1);
unordered_map <ll,ll> mp;
int BSGS(int a,int b,int n,int t){
mp.clear();
int m = sqrt(1.0*n);
ll x = t,p = 1;
b %= n;
for(int i = 0; i < m; ++i, p = p*a%n) mp[p*b%n]=i;
for(ll i = m ;; i += m){
if(mp.count(x = x*p%n)) return i-mp[x];
if(i > n) break;
}
return -1;
}
int exBSGS(int a,int b,int n){ //a^x = b (mod p)
a %= n,b%= n;
if(b == 1) return 0;
if(!a && !b) return 1;
if(!a) return -1;
if(!b){
int res = 0,gd;
while((gd = __gcd(a,n)) != 1){
++res,n /= gd;
if(n == 1) return res;
}
return -1;
}
int res = 0,gd,t = 1;
while((gd = __gcd(a,n)) != 1){
if(b%gd) return -1;
n /= gd,b /= gd;
++res;
t = 1ll*t*(a/gd)%n;
if(t == b) return res;
}
// cout<<a<<" "<<b<<" "<<n<<endl;
int ans = BSGS(a,b,n,t);
if(ans == -1) return -1;
return ans + res;
}
int main(){
// ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("1in.in","r",stdin);
freopen("1out.out","w",stdout);
#endif
int a,b,p;
while(~scanf("%d%d%d",&a,&p,&b)){
if(!a && !b && !p) break;
int ans = exBSGS(a,b,p);
if(ans == -1) puts("No Solution");
else printf("%d\n",ans);
}
}
kuangbin模板
const int mod = 76543;
int hs[mod],head[mod],nxt[mod],id[mod],top;
void insert(int x,int y){
int k = x%mod;
hs[top] = x,id[top] = y,nxt[top] = head[k],head[k] = top++;
}
int find(int x){
int k = x%mod;
for(int i = head[k]; i != -1; i = nxt[i]){
if(hs[i] == x) return id[i];
}
return -1;
}
int BSGS(int a,int b,int n){
memset(head,-1,sizeof head);
top = 1;
if(b == 1) return 0;
int m = sqrt(1.0*n),j;
long long x = 1,p = 1;
for(int i = 0; i < m; ++i, p = p*a%n){
insert(p*b%n,i);
}
for(long long i = m; ; i += m){
if( (j = find(x = x*p%n)) != -1) return i-j;
if(i > n) break;
}
return -1;
}