数学板块学习之离散对数(1)_Baby-Step Giant-Step

离散对数问题

给出 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=kmt
所以原式等价 a k ⋅ m − t = b   ( m o d    n ) a^{k·m-t}=b\ (mod\ \ n) akmt=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=bat (mod  n)(1)
然后从 0 − m 0-m 0m枚举 t t t,将 b ⋅ a t b·a^t bat存入Hash表

m m m开始枚举 m ⋅ k m·k mk,每次加 m m m,其实就是相当于从1开始枚举 k k k,从Hash表中找到第一个满足式 ( 1 ) (1) (1)的解。
此时 x = m ⋅ k − t x=m·k-t x=mkt
我自己的模板

//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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值