POJ_2417 Discrete Logging 普通babystep_gaintstep

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 ;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值