【写在前面】:
其实很早之前就已经知道这个东西了
最近做了一道BSGS的题目,有感而发
决定扯一下淡,顺便加深一下记忆
为啥要把BSGS和逆元一起讲呢?因为BSGS里面也牵涉到了逆元的相关知识(虽然并没有什么关系)
【参考】:
http://www.cnblogs.com/yuiffy/p/3877381.html
http://blog.csdn.net/wyfcyx_forever/article/details/40538515
http://hi.baidu.com/aekdycoin/item/236937318413c680c2cf29d4
(写的很好不过hi.baidu已经SB了TAT)
http://quartergeek.com/bsgs/
http://www.cnblogs.com/mengfanrong/p/4660834.html
http://blog.miskcoo.com/2014/09/linear-find-all-invert
(这个是线性求逆元的)
【线性求逆元】:
我们称 A^(-1) mod p为A在mod p意义下的逆元
显然在p为质数且(A,p)=1时可以用欧拉定理搞定
然A p没有任何联系时,我们可以用扩展欧几里德求出,这样求解[1,n]的逆元复杂度为O(n log n)
我们考虑一个SB的事实p mod p=0
然后我们令p=k*i+r (1<=i<p r<i)
显然k*i+r mod p=0
两边同乘i^(-1)*r^(-1)得到 k*r^(-1)+i^(-1) mod p=0
i^(-1) mod p=-k*r^(-1)
显然k=p/i,r=p%i代入原式可以得到i^(-1) mod p=-p/i*(p%i)^(-1)
因此我们令rev[i]表示i的逆元,那么rev[i]=-(p/i)*rev[p%i]
递推处理即可,复杂度O(N)
同时这篇blog还提供了O(log p)复杂度求出单个逆元
p%i<=p/2,然后就可以递归处理了
【简介】:
首先BSGS的全称是:Baby Step Giant Step
它主要用来求解这样的问题:A^x mod p=B的最小非负整数解
BSGS分为质数版和extend版,我们分开总结一下
【质数版BSGS】:
所谓质数版指的是p为指数的情况
我们考虑p为指数时,根据费马小定理可以知道 0<=x<p
显然暴力枚举的复杂度是O(p)的,当p较大时显然不适用
我们可以这样考虑:令x=C*i+j(其中C为常数)
代入原式可得(A^C)^i*A^j mod p=B
显然我们可以用0<=i<=p/C
于是我们可以用O(C)的时间求出A^C 然后再用O(p/C)的时间枚举i
于是问题就转化为是否存在一个j满足D*A^j mod p=B,D为确定的值
A^j mod p=B/D,其中0<=j<C
我们可以用O(C)的时间预处理出A^j mod p的值,存入map里面
然后可以在log的时间复杂度内查询最小的j满足条件
显然我们取C=sqrt(p),那么整个算法的复杂度就是O(sqrt(p) log sqrt(p))
B/D可以利用扩展欧几里德或者欧拉定理算出来
【extend版BSGS】
如果p不是质数,那么可能会出现gcd(A,p)!=1的时候
我们考虑在求解D*A^j mod p=B时候如果gcd(D,p)!=1时的情况
由于D=A^C,因此就是gcd(A,p)!=1的情况,此时不能用扩展欧几里德求出A^j
我们考虑一个重要的性质:Ad mod Bd = Cd等价于A mod B = C
因此我们考虑对于gcd(A,p)!=1的情况,我们可以暴力消因子
我们考虑A^x mod p=B
我们不断的求出gcd(A,p)直到(A,p)=1为之,令t=gcd(A,p)
如果B mod t!=0显然当前方程无解,那么对应的原方程也无解
我们令总共消掉的数为D,那么消完后的方程等价于(A/D)^x mod (p/D) = B/D
然而这样子做对于A/D还需要求解逆元然后就不好做了
我们这样做:(参考:https://oi.abcdabcd987.com/bsgs/)
D = 1, cnt = 0
while gcd(A, p) != 1:
if (B % gcd(A, p) != 0)
No Solution
B /= gcd(A, p)
p /= gcd(A, p)
D *= A / gcd(A, p)
cnt += 1
那么之后的方程就变成D*A^(x-cnt) mod p=B(注意此时的B,p对应消过因子的后的数)
此时gcd(D,p)=1就可以用BSGS求出x-cnt,然后加上cnt即可
但是上述的方法其实是存在bug的
我们求出的x-cnt>=0,因此x>=cnt,那么x<cnt的解怎么办?
我们知道cnt最多为p中2的个数,因此cnt是O(log p)级别的,我们暴力枚举这一部分的情况即可
【一个很实用的trick】:
我们考虑质数版BSGS
我们不妨令x=C*i-j (1<=i<=p/C)
那么(A^C)^i mod p=B*A^j,我们可以预处理出B*A^j,然后map即可
然后这样似乎没什么大的改进?真的吗?你会求逆矩阵吗,反正我是不会
我们看一下这题:bzoj 4128: Matrix
我们利用这个trick,既不用逆矩阵,也不用hash,直接裸上map即可
不过这么实用的技巧为啥很少人用捏?
【总结】:
简言之,BSGS在求解一类高次同余问题中是非常实用的
而它也可以与各种其他的东西相结合
我们需要针对不同的题目实用不同的做法
当然extend版的BSGS是非常实用的东西
就这样了...
(下面是一些例题)
阅读更多……