問題引入
給定整數,其中互質,求一個非負整數,使得。
因爲加了次數,所以擴展歐幾里得算法就無法實現了,所以我們要使用**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;
}