简介
先看一个式子xy≡z(modp),z是质数
现在只知道x和z,要求y。
大步小步算法(BSGS,Baby Steps Giant Steps)就是解决这个问题。
算法流程
暴搜的枚举范围
根据费马小定理:xp−1≡1。
如果y已经枚举到了p-1了,继续枚举的话就会产生循环。
所以,在暴搜中y的枚举范围就是0……p-1。
如何优化暴搜
我们想一想可不可以用分块来解决枚举的y。
把y分成p−1−−−−√分别枚举行不行?
设m=p−1−−−−√,y=a∗m+b,这样枚举a和b就相当于分块枚举了。
那么现在就变成了xa∗m+b≡z(modp)
把a和b分别放在两边:xb≡x−a∗mz(modp)
我们可以发现左边的xb最多只有m个,完全可以预处理出来放进hash里面。
ll m=ceil(sqrt(p-1));
ll ni=qsm(x,m);ni=qsm(ni,p-2);//因为右边的指数是复数,所以需要逆元
a.clear();
a[1]=m+1;
fo(j,1,m-1){
k=k*x%p;
if(!a[k])a[k]=j;
}
然后枚举右边的a就好了。
fo(i,0,m-1){
ll u=a[y];
if(u){
if(u==m+1)printf("%lld\n",i*m);
else printf("%lld\n",i*m+u);
return;
}
y=y*ni%p;
}
printf("Orz, I cannot find x!\n");
这就是O(p√)的用空间换取时间的大步小步算法。
很优美的暴搜。
推荐题目
经典的裸题SDOI2011 计算器
由于本人是个蒟蒻
对于BSGS算法知道的,也只有这么多了。