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 < 2 31, 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 }

 

你可能感兴趣的:(logging)