您的位置:首页 > 大数据 > 人工智能

POJ_2417 Discrete Logging 普通babystep_gaintstep

2012-05-24 00:28 330 查看
http://poj.org/problem?id=2417

题意:

求A^x = B( mod C )的最小x,其中C是一个质数。

思路:

用普通的babystep_gaint_step即可,具体的做法是这样的,我们把x写成下面这样

的形式:x = i * m + j , 这样上式就可以变成:A^m^i * A^j = B( mod C ),其中m=

ceil( sqrt(C) ),0<=i<m , 0<=j <m,接下去我们先求出所有的A^j % C的值,并且把

它们存到一个hash表中去,接下去就是先处理出A^m%C的值,记作D,现在上式就

变成了这样:D^i * A^j = B( mod C ), 现在我们从0-m-1枚举i,这样D^i的值就

已经知道了,记为DD,下面我们先令A^j 为x,式子就变成了:DD*x = B( mod C )

这个式子是可以通过普通的扩展欧几里得算法求出x的解的(这个方程的x在0-C

内一定会只有一个唯一的解,因为gcd(DD, C) == 1, C是质数),然后在建好的hash

表中查找这个x是否存在,若是存在,则输出此时的i*m+j,就是答案。下面说明一下,

为什么x只需要考虑0-C的解就可以了,如果解存在,则上面已经说明,一定会在0-

C范围内存在一个解,因为是找最小的解,因此这时候的解就是答案;如果不存在

解,我们下面将要说明只需要考虑0-C范围内无解,方程就不会有解了。证明的过程

大致是这样的,首先如果方程在0 -- C内都没有解, 考虑A^x%C的值,由鸽笼原理可

知,余数中势必要出现循环节,而且循环节的长度是C的欧拉函数值,也就是说接下

去的x的余数将进入一个循环,从而将不会得出解了。

PS:2012-8-30日已对部分内容做了修改。

代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
typedef __int64 LL ;
LL A, B , C ;
const int MAXN = 499991 ;
bool hash[MAXN] ;
int idx[MAXN] ;
LL val[MAXN] ;

LL pow_mod(LL a, LL b, LL p){
LL res = 1 , add = a ;
while(b){
if(b & 1){
res = res * add % p ;
}
add = add * add % p ;
b >>= 1 ;
}
return res ;
}
void insert(int id , LL vv){
LL v = vv % MAXN ;
while( hash[v] && val[v]!=vv ){
v ++ ; if(v == MAXN) v -= MAXN ;
}
if( !hash[v] ){
hash[v] = 1 ;
idx[v] = id ; val[v] = vv ;
}
}
void ex_gcd(LL a , LL b, LL& x, LL& y){
if(b == 0){
x = 1 ; y = 0 ;
return ;
}
ex_gcd(b , a%b , x, y) ;
LL t = x ;
x = y ;
y = t - a/b*y ;
}
int found(LL vv){
LL v = vv % MAXN ;
while( hash[v] && val[v]!=vv ){
v++ ; if(v == MAXN) v-=MAXN ;
}
if( !hash[v] )   return -1 ;
return idx[v] ;
}

LL baby_step(LL A, LL B, LL C){
LL M = ceil( sqrt(C*1.0) );
memset(hash , 0 , sizeof(hash));
memset(idx, -1, sizeof(idx));
memset(val , -1, sizeof(val));
LL D = 1  ;
for(int j=0;j<M;j++){
insert( j , D ) ;
D = D * A % C ;
}
LL res = 1 ;
LL x ,y ;
for(int i=0;i<M;i++){
ex_gcd(res , C , x ,y );
LL tmp = x * B % C ;
tmp = (tmp % C + C ) % C ;
int jj = found( tmp ) ;
if(jj != -1){
return LL(i)*M+jj ;
}
res = res * D % C ;
}
return -1 ;
}
int main(){
while(scanf("%I64d %I64d %I64d",&C,&A,&B) == 3){
LL res = baby_step(A,B,C) ;
if(res == -1){
printf("no solution\n");
}
else{
printf("%I64d\n",res);
}
}
return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: