离散对数:
考虑方程: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;
}