POJ 2417 Discrete Logging (baby_step,giant_step算法)

转载请注明出处,谢谢 http://blog.csdn.net/ACM_cxlove?viewmode=contents           by---cxlove

题目:http://poj.org/problem?id=2417

高次同余方程。   BL == N (mod P)

求解最小的L。由于数据范围很大,暴力不行

这里用到baby_step,giant_step算法。意为先小步,后大步。

令L=i*m+j  (m=ceil(sqrt(p-1))),

那么原式化为 B^(i*m)*B^j==N(MOD P)————》B^j===N*B^(-i*m)(MOD P)

我们先预处理B^0,B^1,B^2……B^(m-1),存入HASH表。,这一步就是baby-step,每次移动1

然后求出B^-m,枚举i,如果存在B^(-i*m)存在于HASH表中,说明存在解L=i*m+j    ,这一步为giant_step,每次移动m

没写HASH表,相当于数组HASH,用二分查找

至于B^(-m)的求法,可以先求出B的逆元,也就是B^-1。

注意以上解法是最基本的,只能对于gcd(B,P)==1

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define LL __int64
#define N 1000000
using namespace std;
struct Node{
	int idx;
	LL val;
}baby[N];
bool cmp(Node n1,Node n2){
	return n1.val!=n2.val?n1.val<n2.val:n1.idx<n2.idx;
}
LL PowMod(LL a,LL b,LL MOD){
	LL ret=1;
	a%=MOD;
	while(b){
		if(b&1)
			ret=((LL)ret*a)%MOD;
		a=((LL)a*a)%MOD;
		b>>=1;
	}
	return ret;
}
//二分查找
int BinSearch(int m,LL num){
	int low=0,high=m-1,mid;
	while(low<=high){
		mid=(low+high)>>1;
		if(baby[mid].val==num)
			return baby[mid].idx;
		if(baby[mid].val<num)
			low=mid+1;
		else
			high=mid-1;
	}
	return -1;
}
int main(){
	LL p,b,n;
	while(scanf("%lld%lld%lld",&p,&b,&n)!=EOF){
		int m = (int)ceil(sqrt((double)(p - 1)));
		baby[0].idx=0;baby[0].val=1;
		for(int i=1;i<m;i++){
			baby[i].idx=i;     
			baby[i].val=((LL)baby[i-1].val*b)%p;   //b^i
		}
		sort(baby,baby+m,cmp);
		int cnt=1;
		//去年余数相同但是标号大的
		for(int i=1;i<m;i++)
			if(baby[i].val!=baby[cnt-1].val)
				baby[cnt++]=baby[i];
		LL bm=PowMod(PowMod(b,p-2,p),m,p);//先求逆元,再求b^(-m)
		int ans=-1;
		LL tmp=n;
		for(int j=0;j<m;j++){
			//查找(b^(-m))^j
			int pos=BinSearch(cnt,tmp);
			if(pos!=-1){
				ans=j*m+pos;
				break;
			}
			tmp=((LL)tmp*bm)%p;
		}
		if(ans<0)
			puts("no solution");
		else
			printf("%d\n",ans);
	}
	return 0;
}


你可能感兴趣的:(POJ 2417 Discrete Logging (baby_step,giant_step算法))