• 【POJ3243】拓展BSGS(附hash版)


      上一篇博文中说道了baby step giant step的方法(简称BSGS),不过对于XY mod Z = K ,若x和z并不互质,则不能直接套用BSGS的方法了。

      为什么?因为这时候不存在逆元了啊,那么怎么办呢?

      既然是x和z不互质,那么我们就想办法让他们互质,再套用BSGS的解法即可。(这就是所谓的消因子法)

              

    代码如下:

      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 }
    poj3243 (二分版)

      另外,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版代码如下:

      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 }
    poj3243 (hash版)

      在我的理解中呢,hash相当于给每个数给予一个特征,这个特征的种类有限,而且我们根据一个数可以很快知道他的特征。我们存数的事后呢,就把相同特征的存到一起。查找的时候呢,循着这个特征找,就可以很快地找到这个数了。这个特征也要定好,使得随机的数据里面用有着相同特征的个数尽量少。

    2016-02-04 09:14:28

    -----------------------------------------

    2016-08-27 11:29:01 更新

  • 相关阅读:
    《大话设计模式》读书笔记
    设计模式个人笔记
    多线程的单元测试工具
    设计模式六大原则
    时间复杂度和空间复杂度(转)
    排序算法笔记
    《人月神话》读书笔记
    微信公众号开发踩坑记录(二)
    微信公众号开发踩坑记录
    全栈工程师之路
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/5180458.html
Copyright © 2020-2023  润新知