BSGS及擴展BSGS總結(BSGS,map)

蒟蒻哪裏有什麼總結,只能點擊%YL%html

還有這位ZigZagK大佬的blogc++

\(\mbox{BSGS}\)

模板題:洛谷P3846 [TJOI2007]可愛的質數ui

給定\(a,b\)和模數\(\mbox{YL}\),求\(a^x\equiv b(\bmod\mbox{YL})\)\(x\)的最小非負整數解。保證\(\gcd(a,\mbox{YL})=1\)spa

\(k=\lceil\sqrt{\mbox{YL}}\rceil\),令\(x=ky-c\)\(y\in[1,k],c\in[0,k)\),故分解惟一).net

因而有\(a^{ky}\equiv ba^c(\bmod\mbox{YL})\)code

兩邊的取值都只有\(k\)種,枚舉右邊丟進map,再枚舉左邊查找一下便可獲得最小的解。htm

複雜度\(O(\sqrt{\mbox{YL}}\log\sqrt{\mbox{YL}})\)。注意特判掉一些特殊狀況。blog

#include<bits/stdc++.h>
#define LL long long
#define RG register
#define R RG int
using namespace std;
map<int,int>c;
inline LL qpow(RG LL b,R k,RG LL YL){//快速冪
    RG LL a=1;
    for(;k;k>>=1,b=b*b%YL)
        if(k&1)a=a*b%YL;
    return a;
}
int main(){
    R a,b,YL;
    cin>>YL>>a>>b;
    if((b%=YL)==1)return puts("0"),0;//特判×2
    if((a%=YL)==0)return puts("no solution"),0;
    R k=sqrt(YL)+1,y;
    RG LL p,pw=qpow(a,k,YL);
    for(p=b,y=0;y<k;++y,(p*=a)%=YL)//預處理
        c[(int)p]=y;
    for(p=pw,y=1;y<=k;++y,(p*=pw)%=YL)//查找
        if(c.count((int)p))return(cout<<(LL)k*y-c[(int)p]<<endl),0;
    return puts("no solution"),0;//找不到
}

擴展\(\mbox{BSGS}\)

模板題:洛谷P4195 Spoj3105 Mod
雙倍經驗:洛谷SP3105 MOD - Power Modulo Invertedci

能夠解決\(\gcd(a,\mbox{YL})\neq1\)的狀況,核心思想是試探性地約去\(\gcd\)get

同餘方程\(a^x\equiv b(\bmod\mbox{YL})\),能夠提一個\(a\)出來改爲不定方程\(a\cdot a^{x-1}+\mbox{YL}\cdot y=b\),等於說暫時把\(a^{x-1}\)當作了未知數。

\(g=\gcd(a,\mbox{YL})\),學完exgcd以後咱們就知道了若是\(g\nmid b\)則方程組無解。不然就能夠約成\(\frac a g\cdot a^{x-1}+\frac{\mbox{YL}}g\cdot y=\frac b g\)

咱們把約簡後的方程看做一個新的不定方程\(a'\cdot a^{x-1}+\mbox{YL}'\cdot y=b'\),若是\(\gcd(a,\mbox{YL}')\)仍是不爲\(1\)的話,咱們就再從冪裏面拿出一個\(a\)\(\mbox{YL}'\)約。如此循環。

終於在約了\(cnt\)次後,咱們獲得了一個\(\gcd=1\)的方程了,變回來就是\(a'\cdot a^{x-cnt}\equiv b'(\bmod\mbox{YL}')\)

接下來的解法已經屬於常規\(\mbox{BSGS}\)了,不過由於一些細節上的區別仍是再寫一遍。

仍然設\(k=\lceil\sqrt{\mbox{YL}'}\rceil\),令\(x=ky-c\)\(y\in[1,k],c\in[0,k)\)

因而有\(a'\cdot a^{ky}\equiv ba^{cnt}\cdot a^c(\bmod\mbox{YL}')\),其實只是恆等號兩邊多乘了點東西而已。

約分多出來的複雜度是\(O(\log^2\mbox{YL})\),由於最多被約\(\log\)次,它的階小於根號就忽略掉了。又要注意一些特判。

#include<bits/stdc++.h>
#define LL long long
#define RG register
#define R RG int
using namespace std;
map<int,int>c;
inline LL qpow(RG LL b,R k,RG LL YL){
    RG LL a=1;
    for(;k;k>>=1,b=b*b%YL)
        if(k&1)a=a*b%YL;
    return a;
}
int gcd(R x,R y){
    return y?gcd(y,x%y):x;
}
int main(){
    R a,b;RG LL YL;
    cin>>a>>YL>>b;
    while(a||b||YL){
        R x=-1,a1=1,cnt=0,g,k,y,p,pw;
        a%=YL;
        if((b%=YL)==1){x=0;goto L;}//這個特判上面提過
        while((g=gcd(a,YL))!=1){
            if(b%g)goto L;//無解充要條件
            ++cnt;b/=g;YL/=g;
            a1=a/g*(LL)a1%YL;
            if(a1==b){x=cnt;goto L;}
        }//注意這個特判,此時等價於a^{x-cnt}≡1(mod YL)
        c.clear();//多組數據注意清空
        k=sqrt(YL)+1;//常規BSGS過程
        pw=qpow(a,k,YL);
        p=b*qpow(a,cnt,YL)%YL;
        for(y=0;y<k;++y,p=(LL)p*a%YL)
            c[p]=y;
        p=(LL)a1*pw%YL;//多乘一個a1
        for(y=1;y<=k;++y,p=(LL)p*pw%YL)
            if(c.count(p)){x=k*y-c[p];break;}
      L:~x?printf("%d\n",x):puts("No Solution");
        cin>>a>>YL>>b;
    }
    return 0;
}
相關文章
相關標籤/搜索