原根学习笔记
\(\text{原根学习笔记}\)
阶
由欧拉定理,若 \(\gcd(a,m)=1\),那么有 \(a^{\varphi(m)}\equiv1\pmod m\)。那么我们记满足 \(a^n\equiv1\pmod m\) 的最小正整数 \(n\) 为 \(a\) 模 \(m\) 的阶,记作 \(\delta_m(a)\)。
阶有一些良好的性质:
- \(a^1,a^2,a^3,\cdots,a^{\delta_m(a)}\) 模 \(m\) 是两两不同余的。
考虑如果有 \(a^i\equiv a^j\pmod m\),那么显然有 \(a^{|i-j|}\equiv 1\pmod m\)。
-
若 \(a^n\equiv 1\pmod m\),那么 \(\delta_m(a)\mid n\)。
-
若 \(a^p\equiv a^q\pmod m\),那么 \(p\equiv q\pmod {\delta_m(a)}\)。
-
若 \(\gcd(a,m)=1\),那么 \(\delta_m(a^k)=\dfrac{\delta_m(a)}{\gcd(\delta_m(a),k)}\)。
原根
定义
若 \(\gcd(m,g)=1\) 且 \(\delta_m(g)=\varphi(m)\),那么 \(g\) 为模 \(m\) 的原根。
当 \(m\) 为质数时,由阶的性质 1,\(g^i(0<i<m)\) 模 \(m\) 是两两不同余的。
原根的判定
对于满足 \(\gcd(m,g)=1\),那么 \(g\) 为模 \(m\) 原根的充要条件是对于 \(\varphi(m)\) 的任意一个质因子 \(p\),都有 \(g^{\frac {\varphi(m)}p}\not\equiv 1\pmod m\)。
证明:
必要性是显然的,如果存在一个满足上述条件的 \(p\) 那么 \(\delta_m(g)\) 并不是最小的 \(n\)。
对于充分性,如果对于所有 \(p\) 都有 \(g^{\frac{\varphi(m)}p}\not\equiv 1\pmod m\),那么由于 \(g^{\varphi(m)}\equiv 1\pmod m\),有 \(\delta_m(g)\mid \varphi(m)\)。
若 \(g\) 非 \(m\) 的原根,那么 \(\delta_m(g)\neq\varphi(m)\),于是存在 \(\varphi(m)\) 的质因子 \(p\) 使得 \(\delta_m(g)\mid \frac{\varphi(m)}{p}\),显然这个质因子 \(p\) 是满足 \(g^{\frac{\varphi(m)}p}\equiv1\pmod m\),矛盾,于是得证。
原根个数
一个数 \(m\) 若有原根,那么其原根个数为 \(\varphi(\varphi(m))\) 个。
由阶的性质有 \(\delta_m(g^k)=\dfrac{\delta_m(g)}{\gcd(\delta_m(g),k)}=\dfrac {\varphi(m)}{\gcd(\varphi(m),k)}\),因此若 \(\gcd(\varphi(m),k)=1\),会有 \(\delta_m(g^k)=\varphi(m)\),那么 \(g^k\) 同样是 \(m\) 的原根。显然 \(k\) 的个数是 \(\varphi(\varphi(m))\) 级别,于是原根有 \(\varphi(\varphi(m))\) 个。
原根存在定理
一个数 \(m\) 存在原根的条件是当且仅当 \(m=2,4,p^k,2\times p^k\)。其中 \(p\) 是奇质数。
原根的求法
那么按照上边的流程,先判定,寻找最小原根 \(g\),再找出所有的原根 \(g^k\) 即可。
给出 P6091 【模板】原根 的代码:
#include <bits/stdc++.h>
#define int long long
#define N 1000005
using namespace std;
int T;
int n, d;
vector<int>pri;
int phi[N];
bool vis[N];
int rt[N];
void init(int n) {
phi[1] = 1;
for (int i = 2; i <= n; i++) {
if (!vis[i]) pri.push_back(i), phi[i] = i - 1;
for (int j : pri) {
if (j * i > n) break;
vis[j * i] = 1;
if (i % j == 0) {
phi[i * j] = phi[i] * j;
break;
}
phi[i * j] = phi[i] * (j - 1);
}
}
rt[2] = rt[4] = 1;
for (int i : pri) {
if (i == 2) continue;
for (int j = i; j <= n; j *= i) rt[j] = 1;
for (int j = 2 * i; j <= n; j *= i) rt[j] = 1;
}
}
vector<int>v;
void divd(int x) {
v.clear();
for (int i : pri) {
if (i * i > x) break;
if (x % i == 0) {
v.push_back(i);
while (x % i == 0) x /= i;
}
}
if (x > 1) v.push_back(x);
}
int qpow(int x, int y, int mod) {
int ans = 1;
while (y) {
if (y & 1) ans = ans * x % mod;
x = x * x % mod;
y >>= 1;
}
return ans;
}
int chk(int g, int m) {
if (qpow(g, phi[m], m) != 1) return 0;
for (int i : v) {
if (qpow(g, phi[m] / i, m) == 1) return 0;
}
return 1;
}
int fnd(int m) {
for (int i = 1; i < m; i++)
if (chk(i, m)) return i;
return 0;
}
vector<int>ans;
void got(int g, int m) {
ans.clear();
int res = 1;
for (int i = 1; i <= phi[m]; i++) {
res = res * g % m;
if (__gcd(phi[m], i) == 1) ans.push_back(res);
}
}
void solve() {
cin >> n >> d;
if (!rt[n]) cout << "0\n\n";
else {
divd(phi[n]);
got(fnd(n), n);
sort(ans.begin(), ans.end());
cout << ans.size() << '\n';
for (int i = d - 1; i < (int)ans.size(); i += d) cout << ans[i] << ' ';
cout << '\n';
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> T;
init(1e6);
while (T--) solve();
return 0;
}
指标
又称离散对数,可以认为是模意义下的对数运算。
对于 \(m\) 及其原根 \(g\),若 \(\gcd(a,m)=1\),那么必然存在唯一的 \(0\le k<\varphi(m)\) 使得 \(g^k\equiv a\pmod m\),那么 \(k\) 就是以 \(g\) 为底模 \(m\) 的离散对数或指标,记作 \(k=\gamma(a)\)。求指标用 BSGS 是容易的。
指标同样有一些良好的性质。对于 \(\gcd(a,m)=\gcd(b,m)=1\):
- 若 \(a\equiv b\pmod m\),那么 \(\gamma(a)\equiv \gamma(b)\pmod{\varphi(m)}\)。
由阶的性质可以得到。
- \(\gamma(ab)\equiv \gamma(a)+\gamma(b)\pmod{\varphi(m)}\)。
有 \(g^{\gamma(ab)}\equiv ab\equiv g^{\gamma(a)}\times g^{\gamma(b)}\equiv g^{\gamma(a)+\gamma(b)}\pmod m\),再由上一条性质有 \(\gamma(ab)\equiv \gamma(a)+\gamma(b)\pmod{\varphi(m)}\)。
- \(\gamma(a^n)\equiv n\gamma(a)\pmod{\varphi(m)}\)。
由上一条性质是容易推出的。
一般地,我们用指标将在模意义下指数上的问题转化为底数上的问题。

浙公网安备 33010602011771号