原根简单总结

原根

1.定义:

定义 O r d m ( a ) 为使得 a d 1 ( m o d m ) 成立的最小的d(其中a和m互质)
称之为a模m的阶。
阶的性质: O r d m ( a ) | Φ ( m )
由欧拉定理可知:
O r d m ( a ) Φ ( m )
O r d m ( a ) = Φ ( m ) a m m (记住原根是a,不是d!)

2.原根的性质:

1.具有原根的数字仅有以下几种形式: 2 , 4 , p n , 2 · p n (p是奇质数)

2.一个数的最小原根的大小不超过 m 1 4

3.若g是m的一个原根,那么 g d 是m的原根的充分必要条件是 g c d ( d , Φ ( m ) ) = 1 ,
由此可推知一个数的原根个数为 Φ ( Φ ( m ) )

3.求解原根的基本步骤:

  1. 判断一个数是否有原根。(通过性质1,枚举质数即可)
  2. 求得最小原根。(通过性质2,依次枚举 2 m 1 4 判断即可)
  3. 求出所有原根。(通过性质3,枚举次数d即可)

代码实现:
1.筛出质数并进行第一步(顺便把欧拉函数也筛出来):

void get_prime()
{
    is_pri[1]=1;
    for(register int i=2;i<N;i++){
        if(!is_pri[i]) Prime[++tot]=i,phi[i]=i-1;
        for(register int j=1;j<=tot;j++){
            if(1ll*i*Prime[j]>=N) break;
            register int res=i*Prime[j];
            is_pri[res]=1;
            if(i%Prime[j]==0){
                phi[res]=phi[i]*Prime[j];
                break;
            }
            phi[res]=phi[i]*phi[Prime[j]];
        }
    }
}
bool judge(int m)//判断原根有无
{
    if(m==1) return 0;
    if(m==2||m==4) return 1;
    if((m&1)==0) m>>=1;if((m&1)==0) return 0;
    for(int i=2;i<=tot&&(1ll*Prime[i]*Prime[i]<=m);i++)
    {
        if(m%Prime[i]!=0) continue;
        while(m%Prime[i]==0) m/=Prime[i];
        if(m==1) return 1;
        return 0;
    }
    return m;
//这里要return m, 由于Prime[i]*Prime[i]>m即退出的影响
}

2.找出最小原根:

    for(int i=2;1ll*i*i<=phi[m];i++){
    //筛出phi的约数,用于check
        if(phi[m]%i==0){
            st[++top]=i;
            if(i*i!=phi[m]) st[++top]=phi[m]/i;
        }
    }
    int g;
    for(g=2;g<=100;g++)//枚举最小原根
    {
        if(check(g,m)) break;
    }
bool check(int x,int m)
{
    if(Pow(x,phi[m],m)!=1) return 0;
    for(int i=1;i<=top;i++)if(Pow(x,st[i],m)==1) return 0;
    return 1;
}
int Pow(int x,int n,int mod)
{
    int ans=1;
    while(n){
        if(n&1) ans=(1ll*ans*x)%mod;
        x=(1ll*x*x)%mod;
        n>>=1;
    }
    return ans;
}

3.找出所有原根

    int cnt=0;
    register int res=1;
    for(register int i=1;i<=phi[m];i++)
    //由欧拉定理,只用枚举到g^phi[m]
    {
        if(cnt==phi[phi[m]]) break;//个数限制
        res=(1ll*res*g)%m;
        if(gcd(i,phi[m])!=1) continue;
        ans[++cnt]=res;
    }
    sort(ans+1,ans+1+cnt);//由于取了模,要sort
    for(register int i=1;i<=cnt;i++)
    {
        if(i>1) putchar(' ');
        printf("%d",ans[i]);
    }
    puts("");
}

猜你喜欢

转载自blog.csdn.net/element_hero/article/details/79370937