问题引入
给定整数,其中互质,求一个非负整数,使得。
因为加了次数,所以扩展欧几里得算法就无法实现了,所以我们要使用**Baby Step,Giant Step(BSGS)**算法
Baby Step,Giant Step 算法
因为互质,所以可以在模的意义下执行关于a的乘、除法运算。
设,其中,则方程变为。即。
对于所有的,计算出,在Hash表中查找是否存在j,跟新答案即可。时间复杂度为。
参考程序
#include<iostream>
#include<cmath>
#include<map>
using namespace std;
typedef long long LL;
int power(int a,int b,int c){
LL ans=1%c;a%=c;
while(b){
if(b&1)ans=(LL)ans*a%c;
a=LL(a)*a%c;b>>=1;
}
return ans;
}
int baby_step_giant_step(int a,int b,int p){
map<int,int>hash;hash.clear();
b%=p;int t=(int)sqrt(p)+1;
for(int j=0;j<t;j++){
int val=(LL)b*power(a,j,p)%p;//b*a^j
hash[val]=j;
}
a=power(a,t,p);//a^t
if(!a)return !b?1:-1;
for(int i=0;i<=t;i++){
int val=power(a,i,p);//(a^t)^i
int j=hash.find(val)==hash.end()?-1:hash[val];
if(j>=0&&i*t-j>=0)return i*t-j;
}
return -1;
}
int main(){
int c,a,b;
while(~scanf("%d%d%d",&c,&a,&b)){
int ans=baby_step_giant_step(a,b,c);
if(ans==-1)puts("no solution!");
else printf("%d\n",ans);
}
return 0;
}
如果要求最小正整数解,就加一个minn,算一下即可
参考代码
#include<iostream>
#include<cmath>
#include<map>
using namespace std;
typedef long long LL;
int power(int a,int b,int c){
LL ans=1%c;a%=c;
while(b){
if(b&1)ans=(LL)ans*a%c;
a=LL(a)*a%c;b>>=1;
}
return ans;
}
int baby_step_giant_step(int a,int b,int p){
map<int,int>hash;hash.clear();
b%=p;int t=(int)sqrt(p)+1;
for(int j=0;j<t;j++){
int val=(LL)b*power(a,j,p)%p;//b*a^j
hash[val]=j;
}
a=power(a,t,p);//a^t
if(!a)return !b?1:-1;
int minn=-1;
for(int i=0;i<=t;i++){
int val=power(a,i,p);//(a^t)^i
int j=hash.find(val)==hash.end()?-1:hash[val];
if(j>=0&&i*t-j>=0){
if(minn==-1)minn=i*t-j;
else minn=min(minn,i*t-j);
}
}
return minn;
}
int main(){
int c,a,b;
while(~scanf("%d%d%d",&c,&a,&b)){
int ans=baby_step_giant_step(a,b,c);
if(ans==-1)puts("no solution!");
else printf("%d\n",ans);
}
return 0;
}
细心的读者肯定能发现,这里没有用Hash而是用了map,其实map相对于Hash会慢一些(多一个log),但不影响复杂度,能够让代码简洁易懂。下面我们来一个用Hash的
参考代码
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long LL;
int power(int a,int b,int c){
LL ans=1%c;a%=c;
while(b){
if(b&1)ans=(LL)ans*a%c;
a=LL(a)*a%c;b>>=1;
}
return ans;
}
struct Hash{
int x,val,nxt;
}hsh[210000];int cnt,last[210000];
void add(int x,int val){
int now=x%200011;
hsh[++cnt]=(Hash){x,val,last[now]};
last[now]=cnt;
}
int find(int x){
int now=x%200011;
for(int i=last[now];i;i=hsh[i].nxt)
if(hsh[i].x==x)return hsh[i].val;
return -1;
}
int baby_step_giant_step(int a,int b,int p){
cnt=0;memset(last,0,sizeof(last));
b%=p;int t=(int)sqrt(p)+1;
for(int j=0;j<t;j++){
int val=(LL)b*power(a,j,p)%p;
add(val,j);
}
a=power(a,t,p);
if(!a)return !b?1:-1;
int minn=-1;
for(int i=0;i<=t;i++){
int val=power(a,i,p);
int j=find(val);
if(j>=0&&i*t-j>=0){
if(minn==-1)minn=i*t-j;
else minn=min(minn,i*t-j);
}
}
return minn;
}
int main(){
int c,a,b;
while(~scanf("%d%d%d",&c,&a,&b)){
int ans=baby_step_giant_step(a,b,c);
if(ans==-1)puts("no solution!");
else printf("%d\n",ans);
}
return 0;
}
来源:CSDN
作者:zsyzClb
链接:https://blog.csdn.net/zsyzClb/article/details/103206563