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