注: 本文中 (a,b)=gcd(a,b),[a,b]=lcm(a,b) 习惯了(*/ω\*)
阶(指数)
定义
设 (a,m)=1,由欧拉定理知:aφ(m)≡1(modm),则同余方程 ax≡1(modm) 至少有一解
令阶为该同余方程的最小正整数解,记为 δm(a)
δm(a):=min{x:ax≡1(modm)}
性质
命题1
命题1:a1,a2,…,aδm(a) 模 m 两两不同余
证明: 反设 ∃i,j∈[1,δm(a)]且i<j,使得 ai≡aj(modm),则 aj−i≡1(modm),故 δm(a)⩽j−i 与 δm(a)⩾j 矛盾
QED
命题2
命题2:若有 an≡1(modm) 则 δm(a)∣n
证明: 对 n 做对 δm(a) 的带余数除法,则有
n=q⋅δm(a)+r,0⩽r<δm(a)
反设 r>0,则 an≡aq⋅δm(a)+r≡ar≡1(modm)
故 δm(a)⩽r 与 r<δm(a) 矛盾
QED
推论3
推论3:ap≡aq(modm)⇒p≡q(modδm(a))
证明: ap≡aq(modm)⇒ap−q≡1(modm)
由命题2知,δm(a)∣(p−q)⇒p≡q(modδm(a))
QED
下面给出两个有关阶的四则运算的命题
命题4
命题4:若 (a,m)=(b,m)=1,则 δm(ab)=δm(a)δm(b)⟺(δm(a),δ(m)b)=1
证明: “⇒” 由于 aδm(a)≡bδm(b)≡1(modm)
则 (ab)[δm(a),δm(b)]≡1(modm),由命题2知:
δm(a)δm(b)=δm(ab)∣[δm(a),δm(b)]=(δm(a),δm(b))δm(a)δm(b)⇒(δm(a),δm(b))=1
“⇐” 由于 (ab)δm(ab)≡1(modm)
则 (ab)δm(ab)δm(b)≡aδm(ab)δm(b)≡1(modm)
故 δm(a)∣δm(ab)δm(b)⇒δm(a)∣δm(ab)
同理,有 δm(b)∣δm(ab)
⇒δm(a)δm(b)∣δm(ab)
又:(ab)δm(a)δm(b)≡1(modp)⇒δm(ab)∣δm(a)δm(b)
故 δm(ab)=δm(a)δm(b)
QED
命题5
命题5:δm(ak)=(δm(a),k)δm(a)
证明: 由于 ak⋅δm(ak)≡1(modm)
则 δm(a)∣k⋅δm(ak)⇒(δm(a),k)δm(a)∣δm(ak)
又 (ak)(δm(a),k)δm(a)≡aδm(a)(δm(a),k)k≡1(modm)⇒δm(ak)∣(δm(a),k)δm(a)
故 δm(ak)=(k,δm(a))δm(a)
QED
原根
定义
(a,m)=1,a 为 m 的原根 ⟺δm(a)=φ(m)
判定原根
命题1 (判定原根):设 m⩾3,gcd(a,m)=1,则 a 是模 m 的原根的充要条件是,对于 φ(m) 的每个素因数 p,都有 apφ(m)≡1(modm)。
证明: 必要性显然,下面证明充分性。
假设 a 不是模 m 的原根,则存在一个 t<φ(p) 使得 at≡1(modm)。
由裴蜀定理得,一定存在一组 k,x 满足 kt=xφ(m)+gcd(t,φ(m))。
又由欧拉定理得 aφ(m)≡1(modm),故有:
1≡akt≡axφ(m)+gcd(t,φ(m))≡agcd(t,φ(m))(modm)
由于 gcd(t,φ(m))∣φ(m) 且 gcd(t,φ(m))⩽t<φ(m)。
故存在 φ(m) 的素因数 p 使得 gcd(t,φ(m))∣pφ(m)。
则 apφ(m)≡a(t,φ(m))≡1(modm),与条件矛盾。
故假设不成立,原命题成立。
QED
原根存在条件
命题2 (原根存在条件):若 m 的原根存在 ⟺m=1,2,4,pα,2pα,其中 α⩾1,p 为奇素数。
证明:要拆分命题,很是复杂,见 原根存在定理。
最小原根的数量级
王元 于 1959 年证明了若 m 存在原根,则最小的原根不多于 m0.25 级别的。证明略去。
应用
求m的所有原根
例题:P6091 【模板】原根
由阶的性质中的命题5知,若 a 为 m 的原根,则对于 ∀k∈[1,φ(m)],(k,φ(m))=1 有:
δm(ak)=(k,δm(a))δm(a)=(k,φ(m))φ(m)=φ(m)
故在模 m 下,m 的原根一共有 φ(φ(m)) 个。
又由阶的性质中的命题1知,ak 两两不同,则可以通过一个原根生成其他的原根。
又由于最小的原根不多于 m0.25,则可以先暴力枚举出第一个原根,然后利用这一个原根生成其他的原根。
点击显/隐代码
int phi[N], prim[N], cnt, A[N], ans[N];
bool vis[N], chk[N];
void Euler(int n) {//Euler筛
phi[1] = 1;
for (int i = 2; i <= n; i++) {
if (!vis[i]) {
prim[++cnt] = i;
phi[i] = i - 1;
int tmp = i;
//顺便处理p^alpha,2p^alpha的情况
while (tmp <= n && i >= 3) {
if (tmp <= n) chk[tmp] = 1;
if (tmp << 1 <= n) chk[tmp << 1] = 1;
tmp *= i;
}
}
for (int j = 1; j <= cnt && i * prim[j] <= n; j++) {
int p = prim[j];
vis[i * p] = 1;
if (i % p == 0) {
phi[i * p] = phi[i] * p;
break;
} else phi[i * p] = phi[i] * phi[p];
}
}
}
signed main() {
chk[1] = chk[2] = chk[4] = 1;
Euler(1e6);
read(T);
while (T--) {
read(n), read(m);
//没有原根
if (!chk[n]) {printf("0\n\n"); continue;}
//特判两个原根为1的
if (n == 1 || n == 2) {
printf("%lld\n", 1);
if (m == 1) printf("1\n");
else putchar('\n');
continue;
}
//A存所有的phi(m)/p
A[0] = 0;
for (int i = 1; i <= cnt && prim[i] <= phi[n]; i++) {
int p = prim[i];
if (phi[n] % p == 0) A[++A[0]] = phi[n] / p;
}
//找到一个g就直接退出
int g;
for (g = 2; g <= n; g++) if (gcd(g, n) == 1) {
bool fg = 0;
for (int j = 1; j <= A[0]; j++) {
if (ksm(g, A[j], n) == 1) {
fg = 1;
break;
}
}
if (fg) continue;
else break;
}
ans[0] = 0;
//开始生成其他的原根
for (int i = 1; i <= phi[n]; i++) if (gcd(i, phi[n]) == 1)
ans[++ans[0]] = ksm(g, i, n);
//原根从小到大输出
sort(ans + 1, ans + 1 + ans[0]);
printf("%lld\n", phi[phi[n]]);
for (int i = m; i <= ans[0]; i += m) printf("%lld ", ans[i]);
putchar('\n');
}
return 0;
}
例题
ABC212 G
G - Power Pair