「poj2417」BSGS
样题poj2417
引入
BSGS算法,原名Baby Steps Giant Steps,又名大小步算法,拔山盖世算法,北上广深算法——by SLYZoier,数论基本算法之一。
问题
给定a,b,p,求最小的非负整数x,满足ax≡b(modp)
题解
这就是经典的BSGS算法,方法如下:
令x=im−j,m=⌈sqrt(p)⌉,则aim-j≡b(mod p)
移项,得(am)i≡baj(mod p)
首先,从0−m枚举j,将得到的baj的值存入hash表;
然后,从1−m枚举i,计算(am)i,查表,如果有值与之相等,则当时得到的im−j是最小值。
看错博客问错人,用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 }
拓展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