原根学习笔记

\(\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)}\)

由上一条性质是容易推出的。

一般地,我们用指标将在模意义下指数上的问题转化为底数上的问题。

posted @ 2025-04-12 18:06  长安19路  阅读(25)  评论(0)    收藏  举报