BSGS算法(Baby Steps Giant Steps算法,大步小步算法,北上广深算法,拔山盖世算法)
适用问题
对于式子:
$$x^y=z(mod_p)$$
已知x,z,p,p为质数;
求解一个最小非负整数y;
存在一个y,属于[0,p-2](费马小定理)
于是有了一个笨拙的方法,枚举y
枚举y,期望效率:O(P)
寻求一种优化:
对式子变型:
设:$$y=i\sqrt{p}-j$$
则$$x^{i\sqrt{p}-j}=z(mod_p)$$
——这个变型的用意在于把y拆开
枚举y,变成枚举,i,j;
i在1~$\sqrt{p}$之间,j在0~$\sqrt{p}$之间
(根号上取整,其实i,j的范围大可大些——只要保证y不会小于0)
枚举(i,j),期望效率:$O(\sqrt{p}*\sqrt{}p)$
本质上没有优化
接着变型:
$$x^{i\sqrt{p}}=z*x^{j}(mod_p)$$
——这个变型的用意在于真正把y分离为两部分
枚举j,把等号右边的模后得数置于hash_table,此时同一个得数只留最大的j值;
从小到大枚举i,计算等号左边的模后得数,查询hash_table,第一个成功查询的i,与其相应的j,组成$i\sqrt{p}-j$即为最小的y,
期望效率:$O(\sqrt{p}*T(hash))$
效率优异,拔山盖世的bsgs算法,就是这样了;
例题:
[SDOI2011]计算器
代码:
#include<cstring> #include<cstdio> #include<cmath> #define LL long long const int ss=999983; using namespace std; int hash_tab[1000000],tot; struct ss{int nu,next,j; }data[1000000]; void work(); void work1(); void work2(); void work3(); LL Sqr(LL ,int ); int hash(int, int ,int ); LL z,y,p; bool flag; int main() {work(); } void work(){int T,K;scanf("%d%d",&T,&K);while(T--){scanf("%lld%lld%lld",&y,&z,&p);if(K==1)work1();if(K==2)work2();if(K==3)work3();} } void work1(){int i,j,k;printf("%lld\n",Sqr(y,z)); } void work2(){int ans,less;if((!(y%p)&&z)||((y%p)&&!z)){printf("Orz, I cannot find x!\n");return;}printf("%lld\n",Sqr(y%p,p-2)*z%p); } void work3(){long long ysqrtp,sqrtp=ceil(sqrt(p));memset(hash_tab,0,sizeof(hash_tab));memset(data,0,sizeof(data));long long l=1,r=z%p;int i,j;if((!(y%p)&&z)||((y%p)&&!z)){printf("Orz, I cannot find x!\n");return;}ysqrtp=Sqr(y,sqrtp);for(i=0;i<=sqrtp;i++)hash(r,i,0),(r*=y)%=p;for(i=1;i<=sqrtp;i++){(l*=ysqrtp)%=p;if((j=hash(l,0,1))!=-1){printf("%lld\n",i*sqrtp-j);return ;}}printf("Orz, I cannot find x!\n"); } LL Sqr(LL x,int n){LL ret=1;while(n){if(n&1)(ret*=x)%=p;(x*=x)%=p;n>>=1;}return ret; } int hash(int num,int j,int flag){int tem;for(tem=hash_tab[num%ss];tem;tem=data[tem].next){if(data[tem].nu==num){if(!flag&&j>data[tem].j)data[tem].j=j;return data[tem].j;}if(!data[tem].next&&!flag){data[tem].next=++tot;data[tot].j=j;data[tot].nu=num;return -1;}}if(!flag){hash_tab[num%ss]=++tot;data[tot].j=j;data[tot].nu=num;}return -1; }