求解一个最小的x满足给定的方程Bx == N (mod P)
使用baby_step_giant_step算法。也就是先小步后大步算法。
1、令x=i*m+j (m=ceil(sqrt(p))),
那么原式化为 B^(i*m)*B^j==N(MOD P)
B^j==N*B^(-i*m)(MOD P)---------->B^j==N*B^m^(-i)(MOD P)
2、先预处理B^0,B^1,B^2……B^(m-1),存入HASH表,我使用结构体排序然后二分查找,这一步就是baby_step,每次移动1
3、然后快速幂求出B^-m,枚举i,如果存在N*B^(-i*m)存在于HASH表中,说明存在解x=i*m+j,这一步为giant_step,每次移动m
注意以上解法是最基本的,只能对于gcd(B,P)==1,算法的时间复杂度是O(sqrt(P)*log(sqrt(P)))
样题:poj2417
模板:
///大步小步算法
struct baby///小步算法预存的结构体定义
{
long long b,j;
bool operator < (const baby &other)const{
if(b==other.b)return j<other.j;
return b<other.b;
}
}babyv[100005];
///快速幂,x^y%mod
long long q_pow(long long x,long long y,long long mod)
{
long long ans=1;
while(y>0)
{
if(y&1)ans=(ans*x)%mod;
x=(x*x)%mod;
y>>=1;
}
return ans;
}
///小步预存的个数为m的结构体里面查找num
long long find(long long num,long long m)
{
long long l=0,r=m-1,ans=-1;
while(r>=l)
{
long long mid=(r+l)/2;
if(babyv[mid].b>=num){
if(babyv[mid].b==num)
ans=babyv[mid].j;
r=mid-1;
}
else l=mid+1;
}
return ans;
}
///B^x=N(modP)求解x,无解返回-1
long long babystep_giantstep(long long B,long long N,long long P)
{
long long m=ceil(sqrt(P)),ans=1;
for(long long j=0;j<m;j++)///预存操作
{
babyv[j].b=ans;
babyv[j].j=j;
ans=(ans*B)%P;///递推
}
ans=1;
sort(babyv,babyv+m);///预存排序
long long _Bm=q_pow(q_pow(B,P-2,P),m,P);///算出B^(-m)%P的值
for(long long i=0;i<m;i++)
{
long long j=find(N*ans%P,m);///二分查找
if(j!=-1)return i*m+j;///找到返回答案
ans=(ans*_Bm)%P;///继续递推
}
return -1;///找不到答案
}
poj2417代码:点击打开链接
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<cstdlib>
#include<utility>
#include<cstring>
#include<iostream>
#include<algorithm>
#define Inf (1<<29)
#define LL long long
using namespace std;
const int MM=110;
const long long MOD=1000000007;
///大步小步算法
struct baby///小步算法预存的结构体定义
{
long long b,j;
bool operator < (const baby &other)const{
return b<other.b;
}
}babyv[100005];
///快速幂,x^y%mod
long long q_pow(long long x,long long y,long long mod)
{
long long ans=1;
while(y>0)
{
if(y&1)ans=(ans*x)%mod;
x=(x*x)%mod;
y>>=1;
}
return ans;
}
///小步预存的个数为m的结构体里面查找num
long long find(long long num,long long m)
{
long long l=0,r=m-1;
while(r>=l)
{
long long mid=(r+l)/2;