Pku 2417 Discrete Logging
题意:求最小的离散对数B 使得A^B == C (mod P) P是质数 或者判无解
做法:
数论题..对于比我大的同学肯定觉得很简单。。
由欧拉定理 A^phi(P) == 1 (mod P) (phi(prime)=prime-1)
得到 A^(B+phi(P)) == c (mod P) A^(B-Phi(P)) ==c (mod P)
所以可以肯定的一点是 如果 [0,phi(P))内无解 由此式子的周期性必然不会有更多解
一个朴素的想法:枚举 B∈[0,phi(P)) 检验 A^B是否 == C(mod P)
问题又出现了 P是个质数 phi(P)=P-1 必然TLE
所以就必须用空间换时间。
设得到的答案是B B=X*sqrt(P)+Y 注意到X,Y<=sqrt(P)
列式并化简:
A^(X*sqrt(P)+Y) == C (mod P)
(A*sqrt(P))^X*A^Y == C (mod P)
设 T=A*sqrt(P) 原式即 T^X*A^Y == C (mod P)
两边同除以 A^Y 得到 T^X == C/(A^Y) (mod P)
好吧 到现在 做法就已经浮出水面了
我们预处理T^i (mod P) 最多sqrt(P)个 (i<X)
手写hash或者用map直接存下来二元组 (T^X (mod P),X)
然后枚举 Y∈[0,sqrt(P)) 最多sqrt(P)个
对于每个Y 我们求出 C/(A^Y) (mod P) 然后在hash或者map中查找这个值
如果 (C/(A^Y) (mod P),X) 存在 那么说明 X*sqrt(P)+Y 是可以作为答案的
最后答案便是所有满足条件的 X*sqrt(P)+Y 中的最小值。
如果你不知道 C/(A^Y) (mod P) 怎么求
那就继续看下去吧
C/(A^Y) (mod P) == C*((1/A^Y) mod P)
(1/A^Y) (mod P) == (A^Y)^-1 (mod P)
即 (A^Y)^(phi(P)-1) (mod P)
所以 C/(A^Y) (mod P) 就等于C*(A^Y)^(phi(P)-1) (mod P)
这样就解决了此题。
1
#include
<
cstdio
>
2 #include < cstring >
3 #include < cmath >
4 #define Prime 899037
5 #define oo 2000000005
6 #define min(a,b) ((a)<(b)?(a):(b))
7 int P,B,N;
8 int H[Prime],V[Prime];
9 inline int pow( int u, int v)
10 {
11 int ret = 1 ;
12 for ( int tmp = u;v;v >>= 1 ,tmp = (tmp * ( long long )tmp) % P)
13 if (v & 1 ) ret = (ret * ( long long )tmp) % P;
14 return ret;
15 }
16 inline void Hpush( int u, int v)
17 {
18 int t = u % Prime;
19 for (;H[t];)
20 {
21 if (H[t] == u) return ;
22 if ( ++ t == P) t -= P;
23 }
24 H[t] = u,V[t] = v;
25 }
26 inline int Hpop( int u)
27 {
28 int t = u % Prime;
29 for (;H[t];)
30 {
31 if (H[t] == u) return V[t];
32 if ( ++ t == P) t -= P;
33 }
34 return oo;
35 }
36 int main()
37 {
38 for (;scanf( " %d%d%d " , & P, & B, & N) != EOF;)
39 {
40 int ret = oo + 1 ;
41 memset(H, 0 , sizeof (H));
42 memset(V, - 1 , sizeof (V));
43 int sqrtP = ( int )sqrt(( double )P),Bsp = pow(B,sqrtP);
44 for ( int i = 0 ,val = 1 ;i <= sqrtP; ++ i,val = (val * ( long long )Bsp) % P)
45 Hpush(val,i);
46 for ( int i = 0 ,val = 1 ;i <= sqrtP; ++ i,val = (val * ( long long )B) % P)
47 {
48 int h = (N * ( long long )pow(val,P - 2 )) % P,v = Hpop(h);
49 if (v < oo && v * sqrtP + i < ret) ret = v * sqrtP + i;
50 }
51 if (ret > oo) puts( " no solution " );
52 else printf( " %d\n " ,ret);
53 }
54 return 0 ;
55 }
56
2 #include < cstring >
3 #include < cmath >
4 #define Prime 899037
5 #define oo 2000000005
6 #define min(a,b) ((a)<(b)?(a):(b))
7 int P,B,N;
8 int H[Prime],V[Prime];
9 inline int pow( int u, int v)
10 {
11 int ret = 1 ;
12 for ( int tmp = u;v;v >>= 1 ,tmp = (tmp * ( long long )tmp) % P)
13 if (v & 1 ) ret = (ret * ( long long )tmp) % P;
14 return ret;
15 }
16 inline void Hpush( int u, int v)
17 {
18 int t = u % Prime;
19 for (;H[t];)
20 {
21 if (H[t] == u) return ;
22 if ( ++ t == P) t -= P;
23 }
24 H[t] = u,V[t] = v;
25 }
26 inline int Hpop( int u)
27 {
28 int t = u % Prime;
29 for (;H[t];)
30 {
31 if (H[t] == u) return V[t];
32 if ( ++ t == P) t -= P;
33 }
34 return oo;
35 }
36 int main()
37 {
38 for (;scanf( " %d%d%d " , & P, & B, & N) != EOF;)
39 {
40 int ret = oo + 1 ;
41 memset(H, 0 , sizeof (H));
42 memset(V, - 1 , sizeof (V));
43 int sqrtP = ( int )sqrt(( double )P),Bsp = pow(B,sqrtP);
44 for ( int i = 0 ,val = 1 ;i <= sqrtP; ++ i,val = (val * ( long long )Bsp) % P)
45 Hpush(val,i);
46 for ( int i = 0 ,val = 1 ;i <= sqrtP; ++ i,val = (val * ( long long )B) % P)
47 {
48 int h = (N * ( long long )pow(val,P - 2 )) % P,v = Hpop(h);
49 if (v < oo && v * sqrtP + i < ret) ret = v * sqrtP + i;
50 }
51 if (ret > oo) puts( " no solution " );
52 else printf( " %d\n " ,ret);
53 }
54 return 0 ;
55 }
56