[数论]原根与指标,BSGS

刚学了这方面的知识,总结一下。推荐学习数论方面的知识还是看书学习,蒟蒻看的是《初等数论》学的。

这里也推荐几个总结性质的博客,学习大佬的代码和习题。

原根:https://blog.csdn.net/fuyukai/article/details/50894609

BSGS:https://www.cnblogs.com/cjyyb/p/8810050.html

https://blog.csdn.net/sodacoco/article/details/81515576

然后也没什么好说的啦,以下是模板代码:

求一个数的最小原根

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL prm[1000],tot,N,root;

LL Power(LL x,LL p,LL MOD) {
    LL ret=1;
    for (;p;p>>=1) {
        if (p&1) ret=(ret*x)%MOD;
        x=(x*x)%MOD;
    }
    return ret;
}

LL GetRoot(LL n) {
    LL tmp=n-1,tot=0;
    for (LL i=2;i<=sqrt(tmp);i++) {
        if(tmp%i==0) {
            prm[++tot]=i;
            while(tmp%i==0) tmp/=i;
        }
    }
    if (tmp!=1) prm[++tot] = tmp;            //质因数分解
    for (LL g=2;g<=n-1;g++) {
        bool flag = 1;
        for(int i=1;i<=tot;i++)      //检测是否符合条件
            if(Power(g,(n-1)/prm[i],n)==1) { flag=0; break; } 
        if (flag)return g;
    }
    return 0;  //无解 
}

int main() {
    cin >> N;
    cout<<GetRoot(N)<<endl;
    return 0;
}
View Code

普通BSGS:计算a^x≡b(mod p),要求a和p互质。

#include<bits/stdc++.h>
#define MOD 76543  //这是哈希表大小 
using namespace std; 

int hs[MOD],head[MOD],nxt[MOD],id[MOD],top;
void insert(int x,int y) {
    int k=x%MOD;
    hs[top]= x,id[top]=y,nxt[top]=head[k],head[k]=top++;
}

int find(int x) {
    int k=x%MOD;
    for(int i=head[k];i!=-1;i=nxt[i])
        if(hs[i]==x) return id[i];
    return -1;
}

//普通BSGS:计算A^X=B(mod C)求X(A和C互质) 
int BSGS(int a,int b,int c) {
    top=1; memset(head,-1,sizeof(head));  //清空哈希表 
    a%=c; b%=c;  //先取模 
    if(b==1) return 0;
    int m=sqrt(c*1.0),j;
    long long x=1,p=1;
    for(int i=0;i<m;++i,p=p*a%c)
        insert(p*b%c,i);//小步:存的是(a^j*b, j)
    for(long long i=m;;i+=m) {
        if((j=find(x=x*p%c))!=-1) return i-j;  //大步:a^(ms-j)=b(mod c)
        if(i>c) break;
    }
    return -1;  //无解 
}

int main()
{
    int a,b,c; cin>>a>>b>>c;
    cout<<BSGS(a,b,c)<<endl;
    return 0;
}
View Code

拓展BSGS,计算a^x≡b(mod p),但不要求a和p互质。代码学习yyb大佬的,测试:SPOJ-MOD 。

#include<bits/stdc++.h>
#define MOD 76543  //这是哈希表大小 
using namespace std;
typedef long long LL;

LL power(LL x,LL p,LL mod) {
    LL ret=1;
    for (;p;p>>=1) {
        if (p&1) ret=(ret*x)%mod;
        x=(x*x)%mod;
    } 
    return ret;
}

int hs[MOD],head[MOD],nxt[MOD],id[MOD],top;
void insert(int x,int y) {
    int k=x%MOD;
    hs[top]= x,id[top]=y,nxt[top]=head[k],head[k]=top++;
}

int find(int x) {
    int k=x%MOD;
    for(int i=head[k];i!=-1;i=nxt[i])
        if(hs[i]==x) return id[i];
    return -1;
}

//拓展BSGS:计算A^X=B(mod C)求X(不要求A,C互质) 
int exBSGS(int y,int z,int p) {
    y%=p; z%=p;
    if (z==1) return 0;
    int k=0,a=1;
    while(1) {  //消因子 
        int d=__gcd(y,p); if(d==1)break;
        if(z%d) return -1;  //无解 
        z/=d; p/=d; ++k; a=1LL*a*y/d%p;
        if(z==a) return k;
    }
    top=1; memset(head,-1,sizeof(head));  //清空哈希表,BSGS 
    int m=sqrt(p)+1;
    for(int i=0,t=z;i<m;++i,t=1LL*t*y%p) insert(t,i);
    for(int i=1,tt=power(y,m,p),t=1LL*a*tt%p;i<=m;++i,t=1LL*t*tt%p) {
        int B=find(t); if(B==-1) continue;
        return i*m-B+k;
    }
    return -1;
}

int main()
{
    int a,b,c;
    while (scanf("%d%d%d",&a,&c,&b)==3) {
        if (a==0 && b==0 && c==0) break;
        int t=exBSGS(a,b,c);
        if (t==-1) puts("No Solution"); else printf("%d
",t);
    }
    return 0;
}
View Code

题目练习:

洛谷P2485

简单题,分别是求快速幂,逆元,BSGS。

#include<bits/stdc++.h>
#define MOD 76543  //这是哈希表大小 
using namespace std;
typedef long long LL;

LL power(LL x,LL p,LL mod) {
    LL ret=1;
    for (;p;p>>=1) {
        if (p&1) ret=(ret*x)%mod;
        x=(x*x)%mod;
    } 
    return ret;
}

int hs[MOD],head[MOD],nxt[MOD],id[MOD],top;
void insert(int x,int y) {
    int k=x%MOD;
    hs[top]= x,id[top]=y,nxt[top]=head[k],head[k]=top++;
}

int find(int x) {
    int k=x%MOD;
    for(int i=head[k];i!=-1;i=nxt[i])
        if(hs[i]==x) return id[i];
    return -1;
}

//普通BSGS:计算A^X=B(mod C)求X(A和C互质) 
int BSGS(int a,int b,int c) {
    top=1; memset(head,-1,sizeof(head));  //清空哈希表 
    a%=c; b%=c;  //先取模 
    if(b==1) return 0;
    int m=sqrt(c*1.0),j;
    long long x=1,p=1;
    for(int i=0;i<m;++i,p=p*a%c)
        insert(p*b%c,i);//小步:存的是(a^j*b, j)
    for(long long i=m;;i+=m) {
        if((j=find(x=x*p%c))!=-1) return i-j;  //大步:a^(ms-j)=b(mod c)
        if(i>c) break;
    }
    return -1;  //无解 
}

int main()
{
    int T,k; cin>>T>>k;
    while (T--) {
        int y,z,p; scanf("%d%d%d",&y,&z,&p);
        if (k==1) printf("%lld
",power(y,z,p));
        if (k==2) {
            if (y%p==0) puts("Orz, I cannot find x!");
            else printf("%lld
",z%p*power(y,p-2,p)%p);
        }
        if (k==3) {
            if (y%p==0) {puts("Orz, I cannot find x!"); continue;}
            int t=BSGS(y,z,p);
            if (t==-1) puts("Orz, I cannot find x!");
            else printf("%d
",t);
        }
    }
    return 0;
}
View Code

洛谷P3306

完全不会做qwq,蒟蒻只能自闭半天之后看题解,跟着大佬推。这道题很好,细节也很多,值得多思考。

#include<bits/stdc++.h>
#define MOD 76543  //这是哈希表大小 
using namespace std; 
typedef long long LL;

LL power(LL x,LL p,LL mod) {
    LL ret=1;
    for (;p;p>>=1) {
        if (p&1) ret=(ret*x)%mod;
        x=(x*x)%mod;
    }
    return ret;
}

int hs[MOD],head[MOD],nxt[MOD],id[MOD],top;
void insert(int x,int y) {
    int k=x%MOD;
    hs[top]= x,id[top]=y,nxt[top]=head[k],head[k]=top++;
}

int find(int x) {
    int k=x%MOD;
    for(int i=head[k];i!=-1;i=nxt[i])
        if(hs[i]==x) return id[i];
    return -1;
}

//普通BSGS:计算A^X=B(mod C)求X(A和C互质) 
LL BSGS(int a,int b,int c) {
    top=1; memset(head,-1,sizeof(head));  //清空哈希表 
    a%=c; b%=c;  //先取模 
    if(b==1) return 0;
    int m=sqrt(c*1.0),j;
    long long x=1,p=1;
    for(int i=0;i<m;++i,p=p*a%c)
        insert(p*b%c,i);//小步:存的是(a^j*b, j)
    for(long long i=m;;i+=m) {
        if((j=find(x=x*p%c))!=-1) return i-j;  //大步:a^(ms-j)=b(mod c)
        if(i>c) break;
    }
    return -2;  //无解 
}

int main()
{
    int T; cin>>T;
    LL p,a,b,x1,t;
    while (T--) {
        scanf("%lld%lld%lld%lld%lld",&p,&a,&b,&x1,&t);
        if (x1==t) { puts("1"); continue; }
        if (a==0) {
            if (b==t) puts("2"); else puts("-1");
            continue;
        }
        if (a==1) {
            if (b==0) puts("-1");
            else printf("%lld
",((t-x1)%p+p)%p*power(b,p-2,p)%p+1);
            continue;
        }
        int tmp=(t-t*a)%p; tmp=(tmp+p)%p;
        tmp-=b; tmp%=p; tmp=(tmp+p)%p;
        int ttmp=(x1-x1*a)%p; ttmp=(ttmp+p)%p;
        ttmp-=b; ttmp%=p; ttmp=(ttmp+p)%p;
        tmp=tmp*power(ttmp,p-2,p)%p;
        
        printf("%lld
",BSGS(a,tmp,p)+1);
    }
    return 0;
}
View Code

BZOJ 1319

原文地址:https://www.cnblogs.com/clno1/p/10918787.html