这个主要是用来解决这个题:
A^x=B(mod C)(C是质数),都是整数,已知A、B、C求x。
我在网上看了好多介绍,觉得他们写得都不够碉,我看不懂…于是我也来写一发。
先把x=i*m+j,其中m=ceil(sqrt(C)),(ceil是向上取整)。
这样原式就变为A^(i*m+j)=B(mod C),
再变为A^j=B*A^(-m*i) (mod C),
先循环j=0~(C-1),把(A^j,j)加入hash表中,这个就是Baby Steps(现在可以播放Baby Steps-Varsity了)。
然后我们再枚举等号右边,从hash表中找看看有没有,有的话就得到了一组i j,x=i*m+j,得到的这个就是正确解。(为什么这个解一定是正解原理我还没懂……懂了我会贴上来)
所以,接下来要解决的就是枚举B*A^(-m*i) (mod C)这一步(这就是Giant Step,快放Giant Step-Astronauts(May'n・椎名慶治))。
A^(-m*i)相当于1/(A^(m*i)),里面有除法,在mod里不能直接用除法,这时候我们就要求逆元。
/*百度百科:
对xA+yB=z,
变成这样xA = z - yB,取B=C(C就是我们要mod的那个)
推导出 xA % C = z %C
只要 z%C==1 时,就可以求出A的逆元x
但用exgcd求完,x可能是负数,还需要这样一下:x=(x%C+C)%C
//--exgcd介绍完毕--
再看我们的题目,
exgcd(A^(m*i) , C)=z,当C是质数的时候z肯定为1,这样exgcd求得的x就是逆元了。
因为x就是A^(m*i)的逆元,P/(A^(m*i))=P*x,所以
B*A^(-m*i) = B/(A^(m*i)) = B*x(mod C)
这样我们的式子A^j=B*A^(-m*i) (mod C)的等号右边就有了,就是B*x,就问你怕不怕!
枚举i,求出右边在hash里找,找到了就返回,无敌!
1 #include<cstdio>
2 #include<cmath>
3 #include<iostream>
4 #include<cstring>
5 #include<algorithm>
6 #include<cmath>
7 #include<map>
8 #include<set>
9 using namespace std;
10 #define ll __int64
11 #define usint unsigned int
12 #define RE freopen("1.in","r",stdin)
13
14 class hash {
15 public:
16 hash() {
17 memset(a,0xff,sizeof(a));
18 }
19 int locate(ll x) {
20 ll l=x%MOD;
21 while(a[l]!=x&&a[l]!=-1) l=(l+1)%MOD;
22 return l;
23 }
24 void insert(ll x,ll va) {
25 ll l=locate(x);
26 if(a[l]==-1) {
27 a[l]=x;
28 v[l]=va;
29 }
30 }
31 ll get(ll x) {
32 ll l=locate(x);
33 return a[l]==x?v[l]:-1;
34 }
35 void clear() {
36 memset(a,0xff,sizeof(a));
37 }
38 private:
39 static const ll MOD=100007;
40 ll a[MOD+100],v[MOD+100];
41 } S;
42
43 ll exgcd(ll a,ll b,ll &x,ll &y) {
44 ll t,ret;
45 if (!b) {
46 x=1,y=0;
47 return a;
48 }
49 ret=exgcd(b,a%b,x,y);
50 t=x,x=y,y=t-a/b*y;
51 return ret;
52 }
53
54 int main() {///A^x=B(modC) A^j=B*A^(-m*i)(mod C)
55 ll C,A,B;
56 ll m,i,t,D,ans,x,y;
57 while(scanf("%lld%lld%lld",&C,&A,&B)!=EOF) {
58 S.clear();
59 m=ceil(sqrt((double)C));
60 t=1;
61 for(i=0; i<m; i++) { /**One, two, baby steps.Three, four, baby steps.Five, six, baby steps.**/
62 S.insert(t,i);
63 t=t*A%C;
64 }
65 D=1;///此时t=A^m
66 ans=-1;
67 for(i=0; i<m; i++) { /**一歩 Giant Step , 君にとってLittle だとしても**/
68 exgcd(D,C,x,y);///exgcd求逆元,得到x=D^(-i*m)
69 x=((x*B)%C+C)%C;///B*x=B*D^(-i*m)
70 y=S.get(x);
71 //printf("%lld,%lld\n",x,y);
72 if(y!=-1) {
73 ans=i*m+y;
74 break;
75 }
76 D=(D*t)%C;///D=t^i,(t=A^m)
77 }
78 if(ans==-1) printf("no solution\n");
79 else printf("%lld\n",ans);
80 }
81 return 0;
82 }