原根 学习笔记
阶
先看看啥是阶。
由欧拉定理可知,对于 \(a\in\mathbf{Z},m\in\mathbf{N}^*\) ,若 \((a,m)=1\) ,则 \(a^{\varphi(m)}\equiv1\pmod m\) 。
因此满足同余式 \(a^n\equiv1\pmod m\) 的最小正整数 \(n\) 存在,这个 \(n\) 称作 \(a\) 模 \(m\) 的阶,记作 \(\delta_m(a)\) 或 \(\operatorname{ord}_m(a)\) 。
再看看有啥性质。
- \(a,a^2,\dots,a^{\delta_m(a)}\) 模 \(m\) 两两不同余。
- 若 \(a^n\equiv1\pmod m\) ,则 \(\delta_m(a)|n\) 。
- 设 \(m\in\mathbf{N}^*,a\in\mathbf{Z},b\in\mathbf{Z},(a,m)=(b,m)=1\) ,
则 \(\delta_m(ab)=\delta_m(a)\delta_m(b)\) 的充要条件为 \((\delta_m(a),\delta_m(b))=1\) 。
点击查看必要性证明
易知 \(a^{\delta_m(a)}\equiv1\pmod m,b^{\delta_m(b)}\equiv1\pmod m\) ,
则 \((ab)^{[\delta_m(a),\delta_m(b)]}\equiv1\pmod m\) ,
可知 \(\delta_m(ab)|[\delta_m(a),\delta_m(b)]\) ,
又因为 \(\delta_m(ab)=\delta_m(a)\delta_m(b)\) ,
所以 \(\delta_m(a)\delta_m(b)|[\delta_m(a),\delta_m(b)]\) ,
所以 \((\delta_m(a),\delta_m(b))=1\) 。
点击查看充分性证明
易知 \((ab)^{\delta_m(ab)}\equiv1\pmod m\) ,
则 \((ab)^{\delta_m(ab)}\equiv(ab)^{\delta_m(ab)\delta_m(b)}\equiv a^{\delta_m(ab)\delta_m(b)}\equiv1\pmod m\) ,
所以 \(\delta_m(a)|\delta_m(ab)\delta_m(b)\) ,
又因为 \((\delta_m(a),\delta_m(b))=1\) ,
所以 \(\delta_m(a)|\delta_m(ab)\) ,
同理 \(\delta_m(b)|\delta_m(ab)\) ,
所以 \(\delta_m(a)\delta_m(b)|\delta_m(ab)\) ,
又因为 \((ab)^{\delta_m(a)\delta_m(b)}\equiv(a^{\delta_m(a)})^{\delta_m(b)}(b^{\delta_m(b)})^{\delta_m(a)}\equiv1\pmod m\) ,
所以 \(\delta_m(ab)|\delta_m(a)\delta_m(b)\) ,
综上 \(\delta_m(ab)=\delta_m(a)\delta_m(b)\) 。
- 设 \(k\in\mathbf{N},m\in\mathbf{N}^*,a\in\mathbf{Z},(a,m)=1\) ,则 \(\delta_m(a^k)=\dfrac{\delta_m(a)}{(\delta_m(a),k)}\) .
点击查看证明
注意到 \(a^{k\delta_m(a^k)}\equiv (a^k)^{\delta_m(a^k)}\equiv1\pmod m\) ,
则 \(\delta_m(a)|k\delta_m(a^k)\) ,即 \(\dfrac{\delta_m(a)}{(\delta_m(a),k)}|\delta_m(a^k)\) ,
又注意到 \((a^k)^{\frac{\delta_m(a)}{(\delta_m(a),k)}}\equiv(a^{\delta_m(a)})^{\frac{k}{(\delta_m(a),k)}}\equiv1\pmod m\) ,
则 \(\delta_m(a^k)|\dfrac{\delta_m(a)}{(\delta_m(a),k)}\) ,
综上 \(\delta_m(a^k)=\dfrac{\delta_m(a)}{(\delta_m(a),k)}\) 。
原根
说完阶,再看看啥是原根.
设 \(m\in\mathbf{N}^*,g\in\mathbf{Z}\) 。若 \((g,m)=1\) ,且 \(\delta_m(g)=\varphi(m)\) ,则称 \(g\) 为模 \(m\) 的原根。
原根有什么性质呢?
- (原根判定定理)设 \(m\geqslant3,(g,m)=1\) ,则 \(g\) 是模 \(m\) 的原根的充要条件为,对于 \(\varphi(m)\) 的每个素因数 \(p\) ,都有 \(g^{\frac{\varphi(m)}{p}}\not\equiv1\pmod m\) 。
点击查看充分性证明
使用反证法。
当对于 \(\varphi(m)\) 的每个素因数 \(p\) ,都有 \(g^{\frac{\varphi(m)}{p}}\not\equiv 1\pmod m\) 成立时,我们假设存在一个 \(g\),其不是模 \(m\) 的原根。
因为 \(g\) 不是 \(m\) 的原根,则存在一个 \(t<\varphi(m)\) 使得 \(g^t\equiv 1\pmod{m}\) 。
由裴蜀定理得,一定存在一组 \(k,x\) 满足 \(kt=x\varphi(m)+(t,\varphi(m))\) 。
又由欧拉定理得 \(g^{\varphi(m)}\equiv 1\pmod{m}\) ,故有:
由于 \((t, \varphi(m)) \mid \varphi(m)\) 且 \((t, \varphi(m))\leqslant t < \varphi(m)\) 。
故存在 \(\varphi(m)\) 的素因数 \(p\) 使得 \((t, \varphi(m)) \mid \frac{\varphi(m)}{p}\) 。
则 \(g^{\frac{\varphi(m)}{p}}\equiv g^{(t, \varphi(m))}\equiv 1\pmod{m}\) ,与条件矛盾。
故假设不成立,原命题成立。
- (原根个数)若一个数 \(m\) 有原根,则它原根的个数为 \(\varphi(\varphi(m))\) 。
点击查看证明
若 \(m\) 有原根 \(g\) ,则:
所以若 \(\left(k,\varphi(m)\right)=1\) ,则有: \(\delta_m(g^k)=\varphi(m)\) ,即 \(g^k\) 也是模 \(m\) 的原根。
而满足 \(\left(\varphi(m),k\right)=1\) 且 \(1\leq k \leq \varphi(m)\) 的 \(k\) 有 \(\varphi(\varphi(m))\) 个。所以原根就有 \(\varphi(\varphi(m))\) 个。
- (原根存在定理)一个数 \(m\) 存在原根当且仅当 \(m=2,4,p^{\alpha},2p^{\alpha}\) ,其中 \(p\) 为奇素数, \(\alpha\in \mathbf{N}^{*}\) 。
- 证明: 见 OI-Wiki 。
- (最小原根的范围估计)见 OI-Wiki 。
题目
题单: https://vjudge.net/article/5400
洛谷 P6081 【模板】原根
见 https://www.luogu.com.cn/article/d1yftjt7
#include <bits/stdc++.h> using namespace std; const int MAXN=1000010; int t,p,cnt,tot,ctans,fc[MAXN],ans[MAXN],pri[MAXN],rt[MAXN],q[MAXN],phi[MAXN]; void init () { phi[1]=1; for (int i=2;i<=MAXN-10;i++) { if (!q[i]) {pri[++tot]=i,phi[i]=i-1;} for (int j=1;j<=tot&&pri[j]*i<=MAXN-10;j++) { q[i*pri[j]]=1; if (i%pri[j]==0) { phi[i*pri[j]]=phi[i]*pri[j]; break; } phi[i*pri[j]]=phi[i]*(pri[j]-1); } } rt[2]=rt[4]=1; for (int i=2;i<=tot;i++) { for (int j=1;(1ll*j*pri[i])<=MAXN-10;j*=pri[i]) {rt[j*pri[i]]=1;} for (int j=2;(1ll*j*pri[i])<=MAXN-10;j*=pri[i]) {rt[j*pri[i]]=1;} } return; } int gcd (int a,int b) {return (b==0?a:gcd(b,a%b));} int qpow (int a,int b,int p) { int res=1; while (b) { if (b&1) {res=(1ll*res*a)%p;} a=(1ll*a*a)%p; b>>=1; } return res; } void proc (int p) { for (int i=2;i*i<=p;i++) { if (p%i==0) { fc[++cnt]=i; while (p%i==0) {p/=i;} } } if (p>1) {fc[++cnt]=p;} return; } bool chk (int x,int p) { if (qpow(x,phi[p],p)!=1) {return 0;} for (int i=1;i<=cnt;i++) { if (qpow(x,phi[p]/fc[i],p)==1) {return 0;} } return 1; } int findrt (int p) { for (int i=1;i<p;i++) { if (chk(i,p)) {return i;} } return 0; } void getrt (int p,int x) { int prod=1; for (int i=1;i<=phi[p];i++) { prod=(1ll*prod*x)%p; if (gcd(i,phi[p])==1) { ans[++ctans]=prod; } } return; } int main () { init(); scanf("%d",&t); for (int ii=1;ii<=t;ii++) { int wtf; scanf("%d%d",&p,&wtf); if (rt[p]) { ctans=cnt=0; proc(phi[p]); int mn=findrt(p); getrt(p,mn); sort(ans+1,ans+ctans+1); printf("%d\n",ctans); for (int i=1;i<=ctans/wtf;i++) {printf("%d ",ans[i*wtf]);} printf("\n"); } else { printf("0\n\n"); } } return 0; }
POJ 1284 Primitive Roots
直接求 \(\varphi(\varphi(p))\) 即可。
#include <iostream> using namespace std; typedef long long ll; const ll N = 65536; bool np[N + 5]; ll phi[N + 5], pri[N + 5], tot = 0; void init() { phi[1] = 1; for (ll i = 2; i <= N; i++) { if (!np[i]) { pri[++tot] = i; phi[i] = i - 1; } for (ll j = 1; i * pri[j] <= N && j <= tot; j++) { np[i * pri[j]] = true; if (i % pri[j] == 0) { phi[i * pri[j]] = phi[i] * pri[j]; break; } phi[i * pri[j]] = phi[i] * (pri[j] - 1); } } } int main() { ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); init(); ll x; while (cin >> x) cout << phi[phi[x]] << endl; return 0; }
CodeForces 615D Multipliers
设 \(n=\prod_{i} p_i^{r_i}\quad(\forall\lambda,\mu\in[1,m],p_\lambda\ne p_\mu)\) 。
则答案为:
,直接计算即可,注意要处理好有关 \(\frac{1}{2}\) 的问题。
#include <algorithm> #include <cstdio> using namespace std; typedef long long ll; void read(ll &x) { char c = getchar(); ll v = 0, f = 1; while (c < '0' || '9' < c) { if (c == '-') f = -1; c = getchar(); } while ('0' <= c && c <= '9') { v = (v << 1) + (v << 3) + (c ^ 48); c = getchar(); } x = v * f; } const ll mod = 1e9 + 7, mxp = 2 * mod - 2; ll qpow(ll x, ll y) { ll z = 1; while (y) { if (y & 1) z = z * x % mod; x = x * x % mod; y >>= 1; } return z; } const ll M = 2e5 + 5; ll m, p[M], r[M]; bool div2 = false; ll exp = 1, ans = 1; int main() { read(m); for (ll i = 1; i <= m; i++) { read(p[i]); r[p[i]]++; } sort(p + 1, p + m + 1); m = unique(p + 1, p + m + 1) - (p + 1); for (ll i = 1; i <= m; i++) exp = exp * (r[p[i]] + 1) % mxp; for (ll i = 1; i <= m; i++) ans = ans * qpow(p[i], exp * r[p[i]] / 2) % mod; printf("%lld\n", ans); return 0; }
CodeForces 360D Levko and Sets
注意:下面提到的数默认在 \(\bmod p\) 意义下。
设 \(\varphi=\varphi(p)=p-1,g=\gcd(\varphi,\gcd_{i=1}^m b_i)\) , \(G\) 为 \(p\) 的原根。
则集合 \(i\) 为 \(S_i=\{a_i^{gk}|k\in\mathbf{N}\}\) 。
可以找到最小的 \(c_i\) 使 \(a_i^{gc_i}\equiv1\) 。
所以 \(S_i=\{1,a^g,a^{2g},\dots,a^{(c_i-1)g}\}\) ,
即 \(S_i=\{G^0,G^{\frac{\varphi}{c_i}},G^{\frac{2\varphi}{c_i}},\dots,G^{\frac{(c_i-1)\varphi}{c_i}}\}\) 。
设 \(s_i=\frac{\varphi}{c_i}\) ,问题转化为 \(x\) 满足 \(x\in[1,\varphi],\exists s_i|x\) 的个数。
设 \(\operatorname{d}(x)\) 为在 \([1,\varphi]\) 中, \(x\) 倍数的个数。
则答案为 \(\sum\operatorname{d}(c_i)-\sum\operatorname{d}(\operatorname{lcm}(c_i,c_{i+1}))+\dots\) 。
CodeForces 284A Cows and Primitive Roots
直接求 \(\varphi(\varphi(p))\) 即可。
#include <cstdio> using namespace std; void read(int &x) { char c = getchar(); int v = 0, f = 1; while (c < '0' || '9' < c) { if (c == '-') f = -1; c = getchar(); } while ('0' <= c && c <= '9') { v = (v << 1) + (v << 3) + (c ^ 48); c = getchar(); } x = v * f; } const int N = 2000; bool np[N + 5]; int phi[N + 5], pri[N + 5], tot = 0; void init() { phi[1] = 1; for (int i = 2; i <= N; i++) { if (!np[i]) { pri[++tot] = i; phi[i] = i - 1; } for (int j = 1; j <= tot; j++) { int k = i * pri[j]; if (k > N) break; np[k] = true; if (i % pri[j] == 0) { phi[k] = phi[i] * pri[j]; break; } phi[k] = phi[i] * (pri[j] - 1); } } } int p; int main() { init(); read(p); printf("%d\n", phi[phi[p]]); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧