poj 2417 Discrete Logging ---高次同余第一种类型。babystep_gaint_step
Discrete Logging
Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 2831 | Accepted: 1391 |
Description
Given a prime P, 2 <= P < 231, an integer B, 2 <= B < P, and an integer N, 1 <= N < P, compute the discrete logarithm of N, base B, modulo P. That is, find an integer L such that
B^L == N (mod P)
Input
Read several lines of input, each containing P,B,N separated by a space.
Output
For each line print the logarithm on a separate line. If there are several, print the smallest; if there is none, print "no solution".
Sample Input
5 2 1 5 2 2 5 2 3 5 2 4 5 3 1 5 3 2 5 3 3 5 3 4 5 4 1 5 4 2 5 4 3 5 4 4 12345701 2 1111111 1111111121 65537 1111111111
Sample Output
0 1 3 2 0 3 1 2 0 no solution no solution 1 9584351 462803587
经典的高次同余,C是质数,那么A,C互质。A^x = B(mod C)
1 /* 2 3 模板题baby_step. 4 Hash + 扩展欧几里得 +拆分思想 5 6 题意: 7 求A^x = B( mod C )的最小x,其中C是一个质数。 8 思路: 9 用普通的babystep_gaint_step即可,具体的做法是这样的,我们把x写成下面这样 10 的形式:x = i * m + j , 这样上式就可以变成:A^m^i * A^j = B( mod C ),其中m= 11 ceil( sqrt(C) ),0<=i<m , 0<=j <m,接下去我们先求出所有的A^j % C的值,并且把 12 它们存到一个hash表中去,接下去就是先处理出A^m%C的值,记作D,现在上式就 13 变成了这样:D^i * A^j = B( mod C ), 现在我们从0-m-1枚举i,这样D^i的值就 14 已经知道了,记为DD,下面我们先令A^j 为x,式子就变成了:DD*x = B( mod C ) 15 这个式子是可以通过普通的扩展欧几里得算法求出x的解的(这个方程的x在0-C 16 内一定会只有一个唯一的解,因为gcd(DD, C) == 1, C是质数),然后在建好的hash 17 表中查找这个x是否存在,若是存在,则输出此时的i*m+j,就是答案。下面说明一下, 18 为什么x只需要考虑0-C的解就可以了,如果解存在,则上面已经说明,一定会在0- 19 C范围内存在一个解,因为是找最小的解,因此这时候的解就是答案;如果不存在 20 解,我们下面将要说明只需要考虑0-C范围内无解,方程就不会有解了。证明的过程 21 大致是这样的,首先如果方程在0 -- C内都没有解, 考虑A^x%C的值,由鸽笼原理可 22 知,余数中势必要出现循环节,而且循环节的长度是C的欧拉函数值,也就是说接下 23 去的x的余数将进入一个循环,从而将不会得出解了。 24 25 */ 26 27 #include<iostream> 28 #include<cstdio> 29 #include<cstdlib> 30 #include<cstring> 31 #include<math.h> 32 using namespace std; 33 34 typedef __int64 LL; 35 const int MAX=499991; 36 LL A,B,C; 37 bool Hash[MAX]; 38 LL idx[MAX]; 39 LL val[MAX]; 40 41 void Ex_gcd(LL a,LL b,LL &x,LL &y) 42 { 43 if(b==0) 44 { 45 x=1; 46 y=0; 47 return ; 48 } 49 Ex_gcd(b,a%b,x,y); 50 LL hxl=x-(a/b)*y; 51 x=y; 52 y=hxl; 53 } 54 55 LL Euler(LL n) 56 { 57 LL i,temp=n; 58 for(i=2;i*i<=n;i++) 59 { 60 if(n%i==0) 61 { 62 while(n%i==0) 63 n=n/i; 64 temp=temp/i*(i-1); 65 } 66 } 67 if(n!=1) 68 temp=temp/n*(n-1); 69 return temp; 70 } 71 72 void Insert(LL id,LL num) 73 { 74 LL k=num%MAX; 75 while(Hash[k] && val[k]!=num) 76 { 77 k++; 78 if(k==MAX) k=k-MAX; 79 } 80 if(!Hash[k]) 81 { 82 Hash[k]=1; 83 idx[k]=id; 84 val[k]=num; 85 } 86 }// Hash make 87 88 LL found(LL num) 89 { 90 LL k=num%MAX; 91 while(Hash[k] && val[k]!=num) 92 { 93 k++; 94 if(k==MAX) k=k-MAX; 95 } 96 if(!Hash[k]) 97 { 98 return -1; 99 } 100 return idx[k]; 101 }// Hash find 102 103 LL baby_step(LL a,LL b,LL c) 104 { 105 LL M=ceil(sqrt(Euler(c)*1.0)); 106 memset(Hash,false,sizeof(Hash)); 107 memset(idx,-1,sizeof(idx)); 108 memset(val,-1,sizeof(val)); 109 LL D=1; 110 for(LL i=0;i<M;i++) 111 { 112 Insert(i,D); 113 D=D*a%c; 114 }//maek D; 115 116 LL res=1; 117 LL x,y; 118 for(LL i=0;i<M;i++) 119 { 120 Ex_gcd(res,c,x,y); 121 LL tmp=x*b%c; 122 tmp=(tmp%c +c)%c; 123 LL k=found(tmp); 124 if(k!=-1) 125 { 126 return LL(i)*M+k; 127 } 128 res=res*D%c; 129 } 130 return -1; 131 } 132 133 int main() 134 { 135 while(scanf("%I64d%I64d%I64d",&C,&A,&B)>0) 136 { 137 LL res=baby_step(A,B,C); 138 if(res==-1) 139 { 140 printf("no solution\n"); 141 } 142 else printf("%I64d\n",res); 143 } 144 return 0; 145 }