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 }

 

posted @ 2013-08-27 08:35  芷水  阅读(569)  评论(0编辑  收藏  举报