← 全部文章

原根 学习笔记

本文目录(7 节)
  1. 阶
  2. 原根
  3. 判断是否有原根
  4. 求所有原根
  5. 求一个原根
  6. 【模板】P6091 【模板】原根
  7. 参考资料

数论中的一个小概念,也是 NTT 的基础。

阶

若 gcd⁡(a,m)=1\gcd(a,m) = 1,使 al≡1(modm)a^l \equiv 1 \pmod m 成立的最小正整数 ll,称为 aa 关于模 mm 的阶,记为 ordma\text{ord}_m a。

若 ordma=l\text{ord}_m a = l,则 ordmat=lgcd⁡(t,l)\text{ord}_m a^t = \frac{l}{\gcd(t,l)}。

若 ordma=l\text{ord}_m a = l,则 an≡1(modm)a^n \equiv 1 \pmod m 当且仅当 l∣nl|n,特别地,l∣φ(m)l | \varphi(m)。

原根

若 ordmg=φ(m)\text{ord}_mg = \varphi(m),则称 gg 是 mm 的一个原根。

判断是否有原根

若 mm 有原根,则 mm 一定是 2,4,pa,2pa2,4,p^a,2p^a 的形式,这里的 pp 为奇质数,aa 为正整数。

求所有原根

设 gg 为 mm 的一个原根,则对于 s∈[1,φ(m)]s \in [1,\varphi(m)] 且 gcd⁡(s,φ(m))=1\gcd(s, \varphi(m)) = 1,gsg^s 为 mm 的全部原根。因此,若 mm 有原根,则 mm 有 φ(φ(m))\varphi(\varphi(m)) 个原根。

求一个原根

若 gg 是 mm 的原根,当且仅当 gcd⁡(g,m)=1\gcd(g,m) = 1,且对于 φ(m)\varphi(m) 的任意一个质因子 pp,都有 gφ(m)p≢1(modm)g^{\frac{\varphi(m)}{p}} \not\equiv 1 \pmod m。

【模板】P6091 【模板】原根

int m, d, phi, qhi;
vector<pi> p, q;

inline void div(int n, vector<pi> &p, int &phi) {
	p.clear(), phi = n;
	for (int i = 2; i * i <= n; i++)
		if (!(n % i)) {
			phi = 1ll * phi * (i - 1) / i;
			p.pb(mp(i, 0));
			while (!(n % i)) ++p.back().se, n /= i;
		}
	if (n > 1) phi = 1ll * phi * (n - 1) / n, p.pb(mp(n, 1));
}

inline bool pd(int m) {
	if (m & 1) return p.size() == 1u;
	if (m == 2 || m == 4) return 1;
	return p.size() == 2u && p[0] == mp(2, 1);
}

inline int ksm(int a, int b, int m) {
	int c = 1 % m;
	while (b) {
		if (b & 1) c = 1ll * c * a % m;
		a = 1ll * a * a % m, b >>= 1;
	}
	return c;
}

inline bool chk(int g) {
	if (__gcd(g, m) > 1) return 0;
	for (pi o : q)
		if (ksm(g, phi / o.fi, m) == 1) return 0;
	return 1;
}

inline void solve() {
	rd(m), rd(d);
	div(m, p, phi);
	if (!pd(m)) return prints("0\n");
	div(phi, q, qhi);
	int g = 1;
	while (!chk(g)) ++g;
	print(qhi);
	vi ans;
	for (int i = 1, G = g; i <= phi; i++, G = 1ll * G * g % m) {
		if (__gcd(i, phi) > 1) continue;
		ans.pb(G);
	}
	sort(ans.begin(), ans.end());
	for (int i = 1; i <= qhi; i++)
		if (!(i % d)) print(ans[i-1], ' ');
	prints("");
}

int main() {
	int T;
	rd(T);
	while (T--) solve();
	return 0;
}

参考资料

评论

    填写昵称即可留言。评论经站主审核后公开,请勿提交私人信息。

    正在连接评论服务…