回顾一下朴素的BSGS算法,只能用来解p为质数情况下的a^x≡b(mod p)
若p不为质数呢,那就要用扩展BSGS算法了。
其实扩展BSGS算法只是在原有BSGS算法上加了一个能将原方程转移为能用朴素BSGS解决的算方程。
先看这样一个性质:
若A%P=B
则可以表示为A-P*x=B
假设d=gcd(A,P),且B%d=0
则(A/d)%(P/d)=B/d
所以,只要d=gcd(A,P)!=1,且B%d=0,就能一直化简。
过程中,若B%d!=0,则无解。
于是原方程可以表示为a^(x-js)*(a^js/s)≡b/s(mod (p/s))(s为原来求的每个因子di的乘积,js为消除因子的次数)
=> a^(x-js)≡b*a^(-js)(mod (p/s))
换元:x‘=x-js,b’=b*a^(-js),p'=p/s
得 a^(x')≡b'(mod p')
用BSGS解得x',原方程的解为x=x'+js
PS:a^(-js)可以用扩欧求逆元,但有个玄学做法的BSGS是不需要求逆元的,下面是那个玄学做法的程序
ll exbsgs(ll a,ll b,ll p){ if(b==1)return 0; ll js=0; ll k=1; ll cc; while((cc=gcd(a,p))!=1){ if(b%cc!=0){ return -1; } else{ js++; b/=cc; p/=cc; k=k*(a/cc)%p; if(b==k)return js; } } ll m=ceil(sqrt(p)); Hash.clear(); cc=ksm(a,m); ll ss=b; Hash[ss]=0; for(int i=1;i<=m;i++){ ss=ss*a%p; Hash[ss]=i; } for(int i=1;i<=m;i++){ k=k*cc%p; if(Hash.count(k)){ return i*m-Hash[k]+js;//!!这里是-,不是+(玄学操作,我也不懂) } } return -1; }
放道板题:Poj 3243 Clever Y 题目传送门:http://poj.org/problem?id=3243
注意:貌似(其实就是)用map存会TLE,所以最好用哈希表。