离散对数和BSGS算法


离散对数:

考虑方程:ax≡b(mod p),其中a与p互质,求最小正整数x使得方程成立。
这样的x称为离散对数,可以写为logab(mod p)

BSGS算法:

ax≡b(mod p)

设x=i*m-j,其中m=⌈√p⌉,则原方程变为:ai*m-j≡b(mod p)

移项得:(am)i≡baj(mod p)

1.从0到(m-1)枚举j,把baj存入哈希表中

2.从1到m枚举i,查询(am)i是否在哈希表中,如果在则i*m-j就是最小答案。

其他:

1.为什么m取⌈√p⌉?
首先根据费马小定理可推出降幂式子:ak%(p-1)≡ak(mod p),其中a与p互质
原式为ax≡b(mod p),即ax%p=b%p,通过降幂式可转化为ax%(p-1)%p=b%p
式子x%(p-1),当x等于p-1的时候和x等于0的时候结果相同,p的时候和1的时候相同,
因此枚举x的话只需要枚举0到p-2,姑且当作枚举到p。
因此x=i*m-j<=p,令m=⌈√p⌉,那么i最大枚举⌈√p⌉,j最大枚举⌈√p⌉,这样每个枚举都是O(⌈√p⌉),总复杂度也是O(⌈√p⌉)

2.对于不同的j,baj%p可能相同,当相同的时候,在哈希表中存大的j,因为要使得i*m-j尽可能小,则j要尽可能大。


P3846 [TJOI2007]可爱的质数 (BSGS模板)

题意:

给定一个质数p,一个整数b,一个整数n,要求计算出一个最小的L,满足bL≡n(mod p)
如果无解则输出no solution

思路:

BSGS模板

code:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int bsgs(int a,int b,int p){
    //if(a%p==0)return -1;
    unordered_map<int,int>mark;
    int m=ceil(sqrt(p*1.0));
    int now=1;//(a^j)
    for(int j=0;j<=m-1;j++){
        int temp=b*now%p;//b*(a^j)
        mark[temp]=j;
        now=now*a%p;
    }
    int t=now;//a^m,直接用上面的结果now,这样就不用写快速幂了
    now=1;
    for(int i=1;i<=m;i++){
        now=now*t%p;
        if(mark.count(now))return (i*m-mark[now]+p)%p;
    }
    return -1;
}
signed main(){
    int p,b,n;
    cin>>p>>b>>n;
    int ans=bsgs(b,n,p);
    if(ans!=-1){
        cout<<ans<<endl;
    }else{
        cout<<"no solution"<<endl;
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章