离散对数问题
给出a,b,pa,b,pa,b,p,求解ax=b (mod n)a^x=b\ (mod\ \ n)ax=b (mod n)
Baby-Step Giant-Step
简称BSGS算法,(也叫北上广深算法)。复杂度O(n)O(\sqrt{n})O(n),nnn是不是质数都可以。核心是利用较普通查询方式速度更快的Hash表查询。
设m=nm=\sqrt{n}m=n
那么令x=k⋅m−tx=k·m-tx=k⋅m−t
所以原式等价ak⋅m−t=b (mod n)a^{k·m-t}=b\ (mod\ \ n)ak⋅m−t=b (mod n)
即(1)(am)k=b⋅at (mod n)(a^m)^k=b·a^t\ (mod\ \ n)\tag{1}(am)k=b⋅at (mod n)(1)
然后从0−m0-m0−m枚举ttt,将b⋅atb·a^tb⋅at存入Hash表
从mmm开始枚举m⋅km·km⋅k,每次加mmm,其实就是相当于从1开始枚举kkk,从Hash表中找到第一个满足式(1)(1)(1)的解。
此时x=m⋅k−tx=m·k-tx=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;
}