Skip to content

阶与原根

阶与原根是数论中描述模 mm 乘法群 Zm\mathbf{Z}_m^* 结构的重要概念。它们在离散对数、NTT(快速数论变换)等算法中有着广泛应用。

阶 (Order)

定义

mN+,aZm \in \mathbf{N}_+, a \in \mathbf{Z}gcd(a,m)=1\gcd(a, m) = 1。满足同余式

an1(modm)a^n \equiv 1 \pmod m

的最小正整数 nn 称为 aamm,记作 δm(a)\delta_m(a)ordm(a)\operatorname{ord}_m(a)

基本性质

  1. a0,a1,,aδm(a)1a^0, a^1, \dots, a^{\delta_m(a)-1}mm 两两不同余。
  2. an1(modm)a^n \equiv 1 \pmod m 的充要条件是 δm(a)n\delta_m(a) \mid n。由欧拉定理可知 δm(a)φ(m)\delta_m(a) \mid \varphi(m)
  3. δm(a)=\delta_m(a) = \ell,则 δm(ak)=gcd(,k)\delta_m(a^k) = \frac{\ell}{\gcd(\ell, k)}

原根 (Primitive Root)

定义

mN+,gZm \in \mathbf{N}_+, g \in \mathbf{Z}。如果 gcd(g,m)=1\gcd(g, m) = 1δm(g)=φ(m)\delta_m(g) = \varphi(m),则称 gg 是模 mm 的一个 原根

当原根存在时,模 mm 的既约剩余系(与 mm 互素的余数集合)可以表示为 {g1,g2,,gφ(m)}\{g^1, g^2, \dots, g^{\varphi(m)}\}。这在代数上意味着模 mm 乘法群是一个循环群。

存在性定理

mm 存在原根的充要条件是 m{1,2,4,pk,2pk}m \in \{1, 2, 4, p^k, 2p^k\},其中 pp 是奇素数。

原根判定定理

gmg \perp m,则 gg 是模 mm 的原根当且仅当对于 φ(m)\varphi(m) 的任意质因子 pp,都有:

gφ(m)p≢1(modm)g^{\frac{\varphi(m)}{p}} \not\equiv 1 \pmod m

原根个数

若模 mm 存在原根,则原根共有 φ(φ(m))\varphi(\varphi(m)) 个。

求原根的算法

求模 mm 的最小原根通常采用暴力枚举配合判定定理的方法。由于最小原根通常很小,该算法在实践中效率很高。

步骤

  1. 判断 mm 是否存在原根。
  2. 求出 φ(m)\varphi(m) 及其所有不同的质因子 p1,p2,,pkp_1, p_2, \dots, p_k
  3. g=1g=1 开始枚举(通常从 2 开始):
    • 检查 gcd(g,m)\gcd(g, m) 是否为 1。
    • 对每个 pip_i,检查 gφ(m)/pimodmg^{\varphi(m)/p_i} \bmod m 是否不等于 1。
    • 若全部满足,则 gg 即为最小原根。
  4. 若需要所有原根:可以通过最小原根 gg 构造 gk(modm)g^k \pmod m,其中 gcd(k,φ(m))=1\gcd(k, \varphi(m)) = 1

实现 (C++)

cpp
#include <vector>
#include <numeric>
#include <algorithm>

using namespace std;

typedef long long ll;

struct PrimitiveRoot {
    ll power(ll a, ll b, ll m) {
        ll res = 1;
        a %= m;
        while (b) {
            if (b & 1) res = (ll)((__int128)res * a % m);
            a = (ll)((__int128)a * a % m);
            b >>= 1;
        }
        return res;
    }

    ll get_phi(ll n) {
        ll res = n;
        for (ll i = 2; i * i <= n; i++) {
            if (n % i == 0) {
                res = res / i * (i - 1);
                while (n % i == 0) n /= i;
            }
        }
        if (n > 1) res = res / n * (n - 1);
        return res;
    }

    vector<ll> get_prime_factors(ll n) {
        vector<ll> factors;
        for (ll i = 2; i * i <= n; i++) {
            if (n % i == 0) {
                factors.push_back(i);
                while (n % i == 0) n /= i;
            }
        }
        if (n > 1) factors.push_back(n);
        return factors;
    }

    bool has_primitive_root(ll m) {
        if (m == 1 || m == 2 || m == 4) return true;
        if (m % 2 == 0) m /= 2;
        if (m % 2 == 0) return false;
        // 此时 m 应该是 p^k 形式
        for (ll i = 3; i * i <= m; i++) {
            if (m % i == 0) {
                while (m % i == 0) m /= i;
                return m == 1;
            }
        }
        return true; // m 本身是奇素数
    }

    ll find_min_root(ll m) {
        if (!has_primitive_root(m)) return -1;
        ll phi = get_phi(m);
        vector<ll> factors = get_prime_factors(phi);
        
        for (ll g = 1; g < m; g++) {
            if (gcd(g, m) != 1) continue;
            bool ok = true;
            for (ll p : factors) {
                if (power(g, phi / p, m) == 1) {
                    ok = false;
                    break;
                }
            }
            if (ok) return g;
        }
        return -1;
    }
};

总结

阶与原根是模运算下指数性质的核心。掌握原根的判定定理及其求法,是处理离散对数及相关数论变换(如 NTT)的基础。