原根_本原单位根

原根_本原单位根1、原根的定义: 原根,是一个数学符号。设m是正整数,a是整数,若a模m的阶等于φ(m)(m的欧拉函数),则称a为模m的一个原根。 阶:a和模m互质,使ad ≡1(mod m)成立的最小正整数d称为a对模m的阶。例如:22≡1(mod3),2对模3的阶为2。 假设一个数g对于P来说是原根,那么gi

原根_本原单位根"

1、原根的定义:

原根,是一个数学符号。设m是正整数,a是整数,若a模m的阶等于φ(m)(m的欧拉函数),则称a为模m的一个原根。

阶:a和模m互质,使ad ≡1(mod m)成立的最小正整数d称为a对模m的阶。例如:22≡1(mod3),2对模3的阶为2。

假设一个数g对于P来说是原根,那么gi mod p的结果两两不同,且有 1 < g < P , 0 < i < P.那么g可以称为是P的一个原根。

归根到底就是 gP-1 ≡ 1 (mod P)当且仅当质数为P-1的时候成立(P为素数).

求原根目前的做法只能是从2开始枚举,然后暴力判断g^(P-1) = 1 (mod P)是否当且当指数为P-1的时候成立,而由于原根一般都不大,所以可以暴力得到。

2、原根的性质:

(1)可以证明,如果正整数(a,m) = 1 和正整数d满足ad ≡ 1(mod 7),则d整除φ(m)。因此Ordm(a)整除φ(m)。在例子中,

当a = 3 时,我们仅需要验证3的1、2、3和6次方模7的余数即可。

(2)记 δ = Ordm(a),则a1 ,…. aδ-1 构成模m的简化剩余系数。

(3)模m有原根的充要条件是m = 1,2 , 4 , p , 2p , pn , 其中p是奇质数,n是任意正整数。

(4)对正整数(a,m)= 1 , 如果a是模m的原根,那么a是整数n乘法群(即加法群 Z/mZ的可逆元,也就是所有与 m 互素的正整数构成的等价类构成的乘法群)Zn的一个生成元。由于Zn有φ(m)个元素,而它的生成元的个数就是它的可逆元个数,即φ(φ(m))个,因此当模m有原根时,它有φ(φ(m))个原根

3、求质数最小原根

求质数最小原根:对于质数p,φ(p) = p – 1 ,根据费马小定理,ap-1≡1(mod p) 成立a为大于1的整数。所有只需验证没有比p-1小的数k

使得ak≡1(mod p).

而k不需要全部枚举,只需枚举p-1的质因数即可。(如果x为p-1的质因子,且ax ≡ 1(mod p),那么x的倍数nx显然也满足anx ≡ 1(mod p) ,所有p-1不为a对模p的阶(不是最小),即不是原根)。

素数p(3<=p<=1e9),一般对于要多次分解质因数时,可以先筛选出素数,然后再素数里进行质因数分解。

因为这题只需进行一次,可以不需要筛素数,直接分解O(√n)。

首先求质幂分解Φ(m) = p1e1 * p2e2 * …*pkek

然后枚举g,若恒不满足gΦ(m)/p ≡ 1 mod(p) 其中i = 1,2….k.

则g是m的原根。

const int maxn = 1e5+9;
const int N = 1e6+9;
int vis[N], prime[maxn] , len , pf[maxn] , len1;

void Erasieve(){
    rep(i , 2 , N){
        if(!vis[i]){
            prime[++len] = i ;
            for(int j = i * i ; j <= N ; j += i){
                vis[j] = 1 ;
            }
        }
    }
}

void oulasieve(){
    rep(i , 2 , N){
        if(!vis[i]){
            prime[++len] = i ;
        }
        for(int j = 1 ; j <= len && prime[j] * i <= N ; j++){
            vis[prime[j]*i] = 1;
            if(i % prime[j] == 0) break;
        }
    }
}

void divide(int x){
    for(int i = 1 ; i <= len && prime[i] * prime[i] <= x; i++){
        if(x%prime[i]==0){
            pf[++len1] = prime[i];
            while(x % prime[i] == 0){
                x /= prime[i] ;
            }
        }
    }
    if(x > 1) pf[++len1] = x ;
}

/*void divide2(int x){
    for(int i = 2 ; i * i <= x ; i++){
        if(x % i == 0){
            phi[++len1] = i ;
            while(x % i == 0) x /= i ;
        }
    }
}*/

int quickpow(int a , int b , int p){
    int ans = 1 ;
    while(b){
        if(b&1){
            ans = ans * a % p ;
        }
        b >>= 1 ;
        a = a * a % p ;
    }
    return ans ;
}

void solve(){
    oulasieve();
    int p ;
    cin >> p ;
    divide(p-1);
    rep(i , 2 , p-1){
        int flag = 1 ;
        rep(j , 1 , len1){
            if(quickpow(i , (p-1)/pf[j] , p) == 1){
                flag = 0 ;
                break;
            }
        }
        if(flag == 1){
            cout << i << endl;
            break;
        }
    }
}

 

今天的文章原根_本原单位根分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/45604.html

(0)
编程小号编程小号
上一篇 2023-09-06
下一篇 2023-09-06

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注