我是看着\(ppl\)的博客學的,您能夠先訪問\(ppl\)的博客html
求解關於\(x\)的方程
\[y^x=z(mod\ p)\]算法
其中\((y,p)=1\)
作法並不難,咱們把\(x\)寫成一個\(am-b\)的形式
那麼,原式變成了
\(y^{am}=zy^b(mod\ p)\)
咱們求出全部\(b\)可能的取值(0~m-1),而且計算右邊的值
同時用哈希或者\(map\)之類的東西存起來,方便查詢
對於左邊,咱們能夠枚舉全部可能的\(a\),而後直接查右邊的值有沒有相等的便可
複雜度是\(O(max(m,p/m))\)
不難證實\(m=\sqrt(p)\)時複雜度最優spa
因此\(bsgs\)算法的複雜度是\(O(\sqrt(p))\)code
模板題:\(SDOI2011\) 計算器htm
關鍵代碼:blog
int m=sqrt(p)+1;Hash.Clear(); for(RG int i=0,t=z;i<m;++i,t=1ll*t*y%p)Hash.Insert(t,i); for(RG int i=1,tt=fpow(y,m,p),t=tt;i<=m+1;++i,t=1ll*t*tt%p) { int k=Hash.Query(t);if(k==-1)continue; printf("%d\n",i*m-k);return; }
使用\(map\)會多個\(log\),在洛谷上我寫的\(Hash\)目前是跑得最快的。。。get
假設\(gcd(y,p)\neq 1\)怎麼辦?
令\(d=gcd(y,p)\)
將方程改寫成等式形式
\[y^x+kp=z\]
發現此時的\(z\)必需要是\(d\)的倍數,不然無解。
所以,除掉\(d\)
\[\frac{y}{d}y^{x-1}+k\frac{p}{d}=\frac{z}{d}\]
這樣前面的\(y/d\)就是一個係數了,
不斷檢查\(gcd(\frac{z}{d},y)\),一直除到互質爲止
此時的形式就變成了
\[\frac{y^k}{d}y^{x-k}=\frac{z}{d}(mod\ \frac{p}{d})\]
這樣子\(bsgs\)求解以後在還原回去就好了。博客
模板:SPOJ Power Modulo Inverted
關鍵代碼模板
void ex_BSGS(int y,int z,int p) { if(z==1){puts("0");return;} int k=0,a=1; while(233) { int d=__gcd(y,p);if(d==1)break; if(z%d){NoAnswer();return;} z/=d;p/=d;++k;a=1ll*a*y/d%p; if(z==a){printf("%d\n",k);return;} } Hash.clear(); int m=sqrt(p)+1; for(int i=0,t=z;i<m;++i,t=1ll*t*y%p)Hash.Insert(t,i); for(int i=1,tt=fpow(y,m,p),t=1ll*a*tt%p;i<=m;++i,t=1ll*t*tt%p) { int B=Hash.Query(t);if(B==-1)continue; printf("%d\n",i*m-B+k);return; } NoAnswer(); }