POJ 2417 Discrete Logging
Time Limit: 5000MS | Memory Limit: 65536K |
Total Submissions: 4860 | Accepted: 2211 |
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
1 /*BSGS算法+逆元*/
2 這個主要是用來解決這個題:
3
4 A^x=B(mod C)(C是質數),都是整數,已知A、B、C求x。
5
6 我在網上看了好多介紹,覺得他們寫得都不夠碉,我看不懂…于是我也來寫一發。
7
8 先把x=i*m+j,其中m=ceil(sqrt(C)),(ceil是向上取整)。
9
10 這樣原式就變為A^(i*m+j)=B(mod C),
11
12 再變為A^j=B*A^(-m*i) (mod C),
13
14 先循環j=0~(C-1),把(A^j,j)加入hash表中,這個就是Baby Steps
15
16 下面我們要做的是枚舉等号右邊,從hash表中找看看有沒有,有的話就得到了一組i j,x=i*m+j,得到的這個就是正确解。
17
18 是以,接下來要解決的就是枚舉B*A^(-m*i) (mod C)這一步(這就是Giant Step
19
20 A^(-m*i)相當于1/(A^(m*i)),裡面有除法,在mod裡不能直接用除法,這時候我們就要求逆元。
21
22 /*百度百科:
23
24 若ax≡1 mod f, 則稱a關于模f的乘法逆元為x。也可表示為ax≡1(mod f)。
25 當a與f互素時,a關于模f的乘法逆元有唯一解。如果不互素,則無解。如果f為素數,則從1到f-1的任意數都與f互素,即在1到f-1之間都恰好有一個關于模f的乘法逆元。
26 */
27
28 然後我們用超碉的exgcd求逆元,exgcd(擴充歐幾裡德算法)就是在求AB的最大公約數z的同時,求出整數x和y,使xA+yB=z。算法實作就是gcd加幾個語句。
29 然後我們再來看一下exgcd怎麼求逆元:
30 對xA+yB=z,
31
32 變成這樣xA = z - yB,取B=C(C就是我們要mod的那個)
33
34 推導出 xA % C = z %C
35
36 隻要 z%C==1 時,就可以求出A的逆元x
37
38 但用exgcd求完,x可能是負數,還需要這樣一下:x=(x%C+C)%C
39
40 //--exgcd介紹完畢--
41
42 再看我們的題目,
43
44 exgcd(A^(m*i) , C)=z,當C是質數的時候z肯定為1,這樣exgcd求得的x就是逆元了。
45
46 因為x就是A^(m*i)的逆元,P/(A^(m*i))=P*x,是以
47
48 B*A^(-m*i) = B/(A^(m*i)) = B*x(mod C)
49
50 這樣我們的式子A^j=B*A^(-m*i) (mod C)的等号右邊就有了,就是B*x,就問你怕不怕!
51
52 枚舉i,求出右邊在hash裡找,找到了就傳回,無敵!
53
54 /*---------分割線-----------------------*/
55 #include<cmath>
56 #include<iostream>
57 using namespace std;
58 #include<cstdio>
59 #include<cstring>
60 #define mod 100007
61 #define ll long long
62 struct hash
63 {
64 ll a[mod+10],v[mod+10];
65 hash(){memset(a,-1,sizeof(a));}
66 int locate(ll x)
67 {
68 ll l=x%mod;
69 while(a[l]!=x&&a[l]!=-1) l=(l+1)%mod;
70 return l;
71 }
72 void insert(ll x,int i)
73 {
74 ll l=locate(x);
75 if(a[l]==-1)
76 {
77 a[l]=x;
78 v[l]=i;
79 }
80 }
81 int get(ll x)
82 {
83 ll l=locate(x);
84 return (a[l]==x)?v[l]:-1;
85 }
86 void clear()
87 {
88 memset(a,-1,sizeof(a));
89 }
90 }s;
91 void exgcd(ll a,ll b,ll &x,ll &y)
92 {
93 if(b==0)
94 {
95 x=1;
96 y=0;
97 return ;
98 }
99 exgcd(b,a%b,x,y);
100 ll t=x;
101 x=y;
102 y=t-a/b*y;
103 }
104 int main()
105 {
106 ll p,b,n;
107 while(scanf("%I64d%I64d%I64d",&p,&b,&n)==3)
108 {
109 s.clear();
110 ll m=ceil(sqrt(p));
111 ll t=1;
112 for(int i=0;i<m;++i)
113 {
114 s.insert(t,i);
115 t=(t*b)%p;
116 }
117 ll d=1,ans=-1;
118 ll x,y;
119 for(int i=0;i<m;++i)
120 {
121 exgcd(d,p,x,y);
122 x=((x*n)%p+p)%p;
123 y=s.get(x);
124 if(y!=-1)
125 {
126 ans=i*m+y;
127 break;
128 }
129 d=(d*t)%p;
130 }
131 if(ans==-1)
132 printf("no solution\n");
133 else printf("%I64d\n",ans);
134 }
135
136 return 0;
137 }