1. 程式人生 > >擴展BSGS(學習筆記)

擴展BSGS(學習筆記)

return code name article details 我們 學習筆記 new tchar

洛咕

題意:已知a,p,b,求滿足\(a^x≡b(\mod p)\)的最小的自然數x(p不一定是質數).

當p是質數的時候,我們可以直接用普通的BSGS解決.而本題中p不一定是質數,就需要用到擴展的BSGS了.

大佬談擴展BSGS

#include<bits/stdc++.h>
#define LL long long
using namespace std;
struct su{
    int x,y,p;
}b[72727];
int tot,head[72727];
inline int read(){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
    return s*w;
}
inline int gcd(int a,int b){
    if(b==0)return a;
    return gcd(b,a%b);
}
inline int ksm(LL x,int y,int p){
    int cnt=1;
    while(y){
        if(y&1)cnt=(cnt*x)%p;
        x=(x*x)%p;y>>=1;
    }
    return cnt;
}
inline void hash(int x,int y){
    b[++tot].x=x;b[tot].y=y;y%=72727;
    b[tot].p=head[y];head[y]=tot;
}
inline int BSGS(int x,int y,int p,int ex){
    int z=sqrt(p)+1;LL sx=1,sy;
    for(int i=0;i<z;++i){
        hash(i,sx*y%p);
        sx=sx*x%p;
    }
    sy=sx*ex%p;//唯一的改動,這裏需要乘ex
    for(int i=1;i<=z;++i,sy=sy*sx%p)
        for(int j=head[sy%72727];j;j=b[j].p)
            if(b[j].y==sy)return i*z-b[j].x;
    return -1;
}
inline int EX_BSGS(int a,int b,int p){
    if(b==1)return 0;//特判b=1的情況
    LL c=1,z,d;int k=0;
    while(1){
        d=gcd(a,p);
        if(d==1)break;//a,p已經互質了就break掉
        if(b%d)return -1;//d無法整除y,方程無解
        ++k;c=c*(a/d)%p;
//k記錄除了多少次,c表示的是方程的通解
        b/=d;p/=d;//利用上述同余性質
        if(c==b)return k;
    }
    z=BSGS(a,b,p,c);
    return z==-1?z:z+k;
}

int main(){
    while(1){
        int n=read(),mod=read(),m=read();tot=0;
        if(!n&&!m&&!mod)break;
        for(int i=0;i<72727;i++)head[i]=0;
//多組數據初始化
        int ans=EX_BSGS(n%mod,m%mod,mod);
        if(ans==-1)puts("No Solution");
        else printf("%d\n",ans);
    }
    return 0;
}

擴展BSGS(學習筆記)