離散對數和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;
}

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