上一篇博文中说道了baby step giant step的方法(简称BSGS),不过对于XY mod Z = K ,若x和z并不互质,则不能直接套用BSGS的方法了。
为什么?因为这时候不存在逆元了啊,那么怎么办呢?
既然是x和z不互质,那么我们就想办法让他们互质,再套用BSGS的解法即可。(这就是所谓的消因子法)
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<cmath> 7 using namespace std; 8 #define LL long long 9 #define Maxn 40000 10 11 LL x,z,k,aa,m; 12 int cnt,num; 13 int ok; 14 15 struct node 16 { 17 int idx;LL val; 18 }baby[Maxn]; 19 20 LL ax,ay; 21 LL exgcd(LL a,LL b) 22 { 23 if(b==0) {ax=1,ay=0;return a;} 24 LL g=exgcd(b,a%b); 25 LL yy=ay; 26 ay=ax-a/b*ay;ax=yy; 27 return g; 28 } 29 30 bool cmp(node x,node y) {return x.val==y.val?x.idx<y.idx:x.val<y.val;} 31 32 int ffind(LL x) 33 { 34 int head=0,tail=cnt; 35 while(head<tail) 36 { 37 int mid=(head+tail)>>1; 38 if(baby[mid].val==x) return baby[mid].idx; 39 if(baby[mid].val>x) tail=mid-1; 40 else head=mid+1; 41 } 42 if(baby[head].val==x) return baby[head].idx; 43 return -1; 44 } 45 46 bool init() 47 { 48 scanf("%lld%lld%lld",&x,&z,&k); 49 //if(==EOF) return 0; 50 if(x==0&&z==0&&k==0) return 0;k%=z; 51 LL g,bm; 52 bm=1%z;aa=1,num=0;ok=1; 53 //if(k>=z) {ok=0;return 1;} 54 for(int i=0;i<=100;i++) if(bm==k) {printf("%d ",i);ok=0;return 1;} 55 else bm=(bm*x)%z; 56 while((g=exgcd(x,z))!=1) 57 { 58 aa=(aa*x/g)%z,z/=g;num++; 59 if(k%g!=0) {ok=-1;break;} 60 k/=g; 61 } 62 return 1; 63 } 64 65 LL BSGS() 66 { 67 baby[0].idx=0,baby[0].val=aa%z; 68 m=(LL)(ceil(double(sqrt((double)z)))); 69 for(int i=1;i<=m;i++) baby[i].idx=i,baby[i].val=(baby[i-1].val*x)%z; 70 LL bm=1%z,ans=-1,g; 71 for(int i=1;i<=m;i++) bm=(bm*x)%z; 72 g=exgcd(bm,z); 73 bm=ax/g; bm=(bm%(z/g)+(z/g))%(z/g); 74 if(bm==0) bm=z/g; 75 sort(baby,baby+m+1,cmp);cnt=0; 76 for(int i=1;i<=m;i++) if(baby[i].val!=baby[cnt].val) baby[++cnt]=baby[i]; 77 LL tmp=k; 78 for(int i=0;i<=m;i++) 79 { 80 int j; 81 if((j=ffind(tmp))!=-1) 82 { 83 ans=i*m+j; 84 break; 85 } 86 tmp=(tmp*bm)%z; 87 } 88 return ans; 89 } 90 91 int main() 92 { 93 while(1) 94 { 95 LL ans; 96 if(!init()) break; 97 if(ok==0) continue; 98 else if(ok==-1) printf("No Solution "); 99 else 100 { 101 ans=BSGS(); 102 if(ans==-1) printf("No Solution "); 103 else printf("%lld ",ans+num); 104 } 105 } 106 return 0; 107 }
另外,find部分可以不用二分,而用hash解决。感觉大部分情况下还是hash比较快,但是比较耗空间。
把你需要存的数,即x的0~m次方算出来,假设是t,我们设m=1<<16-1,然后用t异或^m得nt(就是取t二进制后的15位进行hash),然后存到hash表里面去。如果t的位置目前没有存数,那么我们就直接存到hash[t]上去,如果t位置已经存了数(因为后15位为t的可能有多种情况),我们就在len除增加一个位置,把nt存到那里面去,然后hash[t].next=len,把位置记录下来,这应该就相当于一条链了。查找的时候循着这条链找下去即可,链的尽头的next用-1标记。
hash版代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<cmath> 7 using namespace std; 8 #define LL long long 9 #define Maxn 40000 10 const int pp=(1<<16)-1; 11 12 LL x,z,k,aa,m; 13 int cnt,num; 14 int ok; 15 16 struct node 17 { 18 int idx,nt; 19 LL val; 20 }baby[2*Maxn];int len; 21 22 LL ax,ay; 23 LL exgcd(LL a,LL b) 24 { 25 if(b==0) {ax=1,ay=0;return a;} 26 LL g=exgcd(b,a%b); 27 LL yy=ay; 28 ay=ax-a/b*ay;ax=yy; 29 return g; 30 } 31 32 void ins(LL now,int id) 33 { 34 int x=now&pp; 35 if(baby[x].idx==-1) {baby[x].idx=id;baby[x].val=now;return;} 36 while(baby[x].val!=now&&baby[x].nt!=-1) x=baby[x].nt; 37 if(baby[x].val==now) return; 38 baby[x].nt=++len; 39 baby[len].nt=-1;baby[len].val=now;baby[len].idx=id; 40 } 41 42 bool init() 43 { 44 scanf("%lld%lld%lld",&x,&z,&k); 45 46 if(x==0&&z==0&&k==0) return 0;k%=z; 47 LL g,bm; 48 bm=1%z;aa=1,num=0;ok=1; 49 50 for(int i=0;i<=100;i++) if(bm==k) {printf("%d ",i);ok=0;return 1;} 51 else bm=(bm*x)%z; 52 while((g=exgcd(x,z))!=1) 53 { 54 z/=g,aa=(aa*x/g)%z;num++; 55 if(k%g!=0) {ok=-1;break;} 56 k/=g; 57 } 58 59 return 1; 60 } 61 62 int ffind(LL now) 63 { 64 int x=now&pp; 65 if(baby[x].idx==-1) return -1; 66 while(baby[x].val!=now&&baby[x].nt!=-1) x=baby[x].nt; 67 if(baby[x].val!=now) return -1; 68 return baby[x].idx; 69 } 70 71 LL BSGS() 72 { 73 m=(LL)(ceil(double(sqrt((double)z)))); 74 75 76 for(int i=0;i<=pp;i++) baby[i].idx=baby[i].nt=-1; 77 78 LL now=aa%z; len=pp; 79 for(int i=0;i<=m;i++) {ins(now,i);now=(now*x)%z;} 80 81 LL bm=1%z,ans=-1; 82 for(int i=1;i<=m;i++) bm=(bm*x)%z; 83 LL g=exgcd(bm,z); 84 bm=ax/g; bm=(bm%(z/g)+(z/g))%(z/g); 85 if(bm==0) bm=z/g; 86 87 LL tmp=k; 88 for(int i=0;i<=m;i++) 89 { 90 int j; 91 if((j=ffind(tmp))!=-1) 92 { 93 ans=i*m+j; 94 break; 95 } 96 tmp=(tmp*bm)%z; 97 } 98 return ans; 99 } 100 101 int main() 102 { 103 while(1) 104 { 105 LL ans; 106 if(!init()) break; 107 if(ok==0) continue; 108 else if(ok==-1) printf("No Solution "); 109 else 110 { 111 ans=BSGS(); 112 if(ans==-1) printf("No Solution "); 113 else printf("%lld ",ans+num); 114 } 115 } 116 return 0; 117 }
在我的理解中呢,hash相当于给每个数给予一个特征,这个特征的种类有限,而且我们根据一个数可以很快知道他的特征。我们存数的事后呢,就把相同特征的存到一起。查找的时候呢,循着这个特征找,就可以很快地找到这个数了。这个特征也要定好,使得随机的数据里面用有着相同特征的个数尽量少。
2016-02-04 09:14:28
-----------------------------------------
2016-08-27 11:29:01 更新