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算法,就是这样了;
例题:
代码:
#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; }
时间: 2024-10-30 18:37:59