「poj2417」BSGS

样题poj2417

引入

BSGS算法,原名Baby Steps Giant Steps,又名大小步算法,拔山盖世算法,北上广深算法——by SLYZoier,数论基本算法之一。

问题

给定a,b,p,求最小的非负整数x,满足axb(modp)

题解

这就是经典的BSGS算法,方法如下: 
x=imjm=⌈sqrt(p),则aim-jb(mod p) 

移项,得(am)ibaj(mod p) 
首先,从0m枚举j,将得到的baj的值存入hash表; 
然后,从1m枚举i,计算(am)i,查表,如果有值与之相等,则当时得到的imj是最小值。

看错博客问错人,用map搞了好久发现TLE,最后还是用的拉链。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<iostream>
 4 #include<cmath>
 5 #include<cstring>
 6 #include<map>
 7 #include<set>
 8 using namespace std;
 9 #define LL long long 
10 const int mod=77877;
11 int nxt[mod],head[mod],tot,key[mod],val[mod];
12 LL ans;
13 LL qpow(LL a,LL b,LL c)
14 {
15     LL re=1;
16     for(;b;a=a*a%c,b=b>>1)
17     if(b&1)re=re*a%c;
18     return re;
19 }
20 void insert(int k,int v)
21 {
22     int tmp=k%mod;
23     tot++;
24     key[tot]=k;val[tot]=v;
25     nxt[tot]=head[tmp];
26     head[tmp]=tot;
27 }
28 int find(int x)
29 {
30     for(int tmp=head[x%mod];tmp;tmp=nxt[tmp])
31     {
32         if(key[tmp]==x)return val[tmp];
33     }
34     return -1;
35 }
36 int BSGS(LL a,LL b, LL p)
37 {
38     tot=0;memset(head,0,sizeof(head));
39     LL m=ceil(sqrt(p));
40     if(b==1){ans=0;return 1;}
41     LL x=b,y=qpow(a,m,p);
42     for(int i=0;i<m;i++)
43     {
44         insert(x,i);
45         x=x*a%p;
46     }
47     x=y;
48     for(int i=1;i<=m;i++)
49     {
50         int j=find(x);
51         if(j!=-1)
52         {
53             ans=i*m-j;
54             return 1;
55         }
56         x=x*y%p;    
57     }
58     return -1;
59 }
60 int main()
61 {
62     freopen("std.in","r",stdin);
63     freopen("std.out","w",stdout);
64     LL n,b,p;
65     while(~scanf("%lld%lld%lld",&p,&b,&n))
66     {
67         if(BSGS(b,n,p)==-1)
68         printf("no solution\n");
69         else printf("%lld\n",ans);
70     }
71     return 0;
72 }
View Code

拓展BSGS

 

如果a跟p不互质,那该怎么办?

其实只需要加一小段代码就可以。

首先,我们知道:

A%P=B,那么就是A-P*x=B,如果d=gcd(A,P),且B%d==0,那么(A/d)%(P/d)=B/d是成立的。

那么我们就在A与P仍有不为一的公因数的时候,不断地从a^x中拿出一个a与c约分。过程中如果b%d!=0,那么在x>T的时候无解。

LL D=1%P; LL g=0,d;
while(  ( d=gcd(A,P)   )  !=1 )
{        
        if(B%d)return -1;
        B/=d;P/=d;
        g++;D=D*(A/d)%P;
}

 最后我们的方程就变为了k*a^(x-g) == b' (%p')再重新推导一下就ok,最后的答案要加上g

 

posted @ 2018-01-21 15:48  岚之川  阅读(182)  评论(0编辑  收藏  举报