什么是阶

( a , m ) = 1 (a,m)=1 (a,m)=1,则使 a l 1 <mtext>   </mtext> ( m o d <mtext>   </mtext> m ) a^l\equiv1~(mod~m) al1 (mod m) 的最小 l l l,称之为 a a a 关于模 m m m 的阶,记为 o r d m a ord_m a ordma
举个例子:
比如要求 2 2 2 7 7 7 的阶,可以一一列举 2 2 2 的幂次:
2 1 2 <mtext>   </mtext> ( m o d <mtext>   </mtext> 7 ) 2^1 \equiv 2~(mod~7) 212 (mod 7)
2 2 4 <mtext>   </mtext> ( m o d <mtext>   </mtext> 7 ) 2^2 \equiv 4~(mod~7) 224 (mod 7)
2 3 1 <mtext>   </mtext> ( m o d <mtext>   </mtext> 7 ) 2^3 \equiv 1~(mod~7) 231 (mod 7)
2 4 2 <mtext>   </mtext> ( m o d <mtext>   </mtext> 7 ) 2^4 \equiv 2~(mod~7) 242 (mod 7)
2 5 4 <mtext>   </mtext> ( m o d <mtext>   </mtext> 7 ) 2^5 \equiv 4~(mod~7) 254 (mod 7)
2 6 1 <mtext>   </mtext> ( m o d <mtext>   </mtext> 7 ) 2^6 \equiv 1~(mod~7) 261 (mod 7)
于是可以看出, 2 2 2 7 7 7 的阶为 3 3 3



阶的性质

  1. 根据欧拉定理,我们有 a φ ( m ) 1 <mtext>   </mtext> ( m o d <mtext>   </mtext> m ) a^{\varphi(m)}\equiv 1~(mod~m) aφ(m)1 (mod m)
    于是 o r d m a φ ( m ) ord_m a \mid \varphi(m) ordmaφ(m)
  2. a x 1 <mtext>   </mtext> ( m o d <mtext>   </mtext> m ) a^x\equiv1~(mod~m) ax1 (mod m) 时, o r d m a x ord_m a \mid x ordmax
  3. 阶相当于最小循环节,即 a x a x + o r d m a <mtext>   </mtext> ( m o d <mtext>   </mtext> m ) a^x\equiv a^{x+ord_m a}~(mod~m) axax+ordma (mod m)。因此 a 1 , a 2 , . . . . , a o r d m a a^1,a^2,....,a^{ord_m a} a1,a2,....,aordma 构成模 m m m 意义下的一个既约剩余系。从上述例子也可以看出,如 2 1 2 4 <mtext>   </mtext> ( m o d <mtext>   </mtext> 7 ) 2^1 \equiv 2^4~(mod~7) 2124 (mod 7)
  4. o r d m a t = o r d m a gcd ( o r d m a , t ) ord_m a^t=\frac{ord_m a}{\gcd(ord_m a,t)} ordmat=gcd(ordma,t)ordma,证明如下:
    a t l 1 <mtext>   </mtext> ( m o d <mtext>   </mtext> m ) a^{t*l}\equiv 1~(mod~m) atl1 (mod m)时, o r d m a t l , t t l ord_m a\mid t*l,t\mid t*l ordmatl,ttl,因此 l l l 最小时, t l t*l tl 应为 l c m ( t , o r d m a ) lcm(t,ord_m a) lcm(t,ordma),可以推得 l = o r d m a gcd ( o r d m a , t ) l=\frac{ord_m a}{\gcd(ord_m a,t)} l=gcd(ordma,t)ordma


原根

o r d m a = φ ( m ) ord_m a=\varphi(m) ordma=φ(m) 时,称 a a a 为关于 m m m 的原根。
也就是说,使得 a x 1 <mtext>   </mtext> ( m o d <mtext>   </mtext> m ) a^x\equiv 1~(mod~m) ax1 (mod m) 成立的最小 x x x φ ( m ) \varphi(m) φ(m)
举个例子:
7 7 7 的原根是 3 3 3,因为:
3 1 3 <mtext>   </mtext> ( m o d <mtext>   </mtext> 7 ) 3^1\equiv3~(mod~7) 313 (mod 7)
3 2 2 <mtext>   </mtext> ( m o d <mtext>   </mtext> 7 ) 3^2\equiv2~(mod~7) 322 (mod 7)
3 3 6 <mtext>   </mtext> ( m o d <mtext>   </mtext> 7 ) 3^3\equiv6~(mod~7) 336 (mod 7)
3 4 4 <mtext>   </mtext> ( m o d <mtext>   </mtext> 7 ) 3^4\equiv4~(mod~7) 344 (mod 7)
3 5 5 <mtext>   </mtext> ( m o d <mtext>   </mtext> 7 ) 3^5\equiv5~(mod~7) 355 (mod 7)
3 6 1 <mtext>   </mtext> ( m o d <mtext>   </mtext> 7 ) 3^6\equiv1~(mod~7) 361 (mod 7)
于是只有 3 φ ( 7 ) 1 <mtext>   </mtext> ( m o d <mtext>   </mtext> 7 ) 3^{\varphi(7)}\equiv 1~(mod~7) 3φ(7)1 (mod 7)
再举一个非素数的例子,比如 5 5 5 18 18 18 的一个原根。 φ ( 18 ) = 6 \varphi(18)=6 φ(18)=6
5 1 5 <mtext>   </mtext> ( m o d <mtext>   </mtext> 18 ) 5^1\equiv 5~(mod~18) 515 (mod 18)
5 2 7 <mtext>   </mtext> ( m o d <mtext>   </mtext> 18 ) 5^2\equiv 7~(mod~18) 527 (mod 18)
5 3 17 <mtext>   </mtext> ( m o d <mtext>   </mtext> 18 ) 5^3\equiv 17~(mod~18) 5317 (mod 18)
5 4 13 <mtext>   </mtext> ( m o d <mtext>   </mtext> 18 ) 5^4\equiv 13~(mod~18) 5413 (mod 18)
5 5 11 <mtext>   </mtext> ( m o d <mtext>   </mtext> 18 ) 5^5\equiv 11~(mod~18) 5511 (mod 18)
5 6 1 <mtext>   </mtext> ( m o d <mtext>   </mtext> 18 ) 5^6\equiv 1~(mod~18) 561 (mod 18)
于是最小的 x x x 使得 5 x 1 <mtext>   </mtext> ( m o d <mtext>   </mtext> 18 ) 5^x\equiv 1~(mod~18) 5x1 (mod 18) φ ( 18 ) \varphi(18) φ(18),也就是 6 6 6



原根的性质

  1. g g g 为原根时, g 1 , g 2 , . . . . , g φ ( m ) g^1,g^2,....,g^{\varphi(m)} g1,g2,....,gφ(m) 构成模 m m m 意义下的既约剩余系。
    从上面 5 5 5 18 18 18 的原根可以看到, 5 1 5^1 51 5 6 5^6 56 18 18 18 之后恰好是 6 6 6 个和 18 18 18 互质的数。
    具体证明也不难,因为 g g g m m m 互质,因此 g x g^x gx m m m 互质,总共有 φ ( m ) \varphi(m) φ(m) x x x,于是生成了 φ ( m ) \varphi(m) φ(m) 个与 m m m 互质的数,也就是 m m m 的既约剩余系。
  2. 如果 m m m 有原根,那么 m m m 总共有 φ ( φ ( m ) ) \varphi(\varphi(m)) φ(φ(m)) 个原根。
    证明一下:
    g g g m m m 的一个原根。那么所有原根肯定存在于 g 1 , g 2 , . . . , g φ ( m ) g^1,g^2,...,g^{\varphi(m)} g1,g2,...,gφ(m) 中,因为原根肯定与 m m m 互质。那么我们考虑 g g g 的幂次。
    o r d m g t = φ ( m ) ord_m g^t=\varphi(m) ordmgt=φ(m) 时, g t g^t gt m m m 的原根,我们来看看这样的 t t t 有多少个。由阶的性质 4 4 4 o r d m g t = φ ( m ) gcd ( φ ( m ) , t ) = φ ( m ) ord_m g^t=\frac{\varphi(m)}{\gcd(\varphi(m),t)}=\varphi(m) ordmgt=gcd(φ(m),t)φ(m)=φ(m) 时, gcd ( φ ( m ) , t ) = 1 \gcd(\varphi(m),t)=1 gcd(φ(m),t)=1,也就是说,这样的 t t t φ ( φ ( m ) ) \varphi(\varphi(m)) φ(φ(m)) 个。
  3. 从上面的证明我们可以看到,若 g g g m m m 的一个原根,则所有原根集合为 { g s 1 s φ ( m ) , ( s , φ ( m ) = 1 ) } \{g^s\mid 1\leq s \leq \varphi(m),(s,\varphi(m)=1)\} {gs1sφ(m),(s,φ(m)=1)}


原根的作用

原根的最大意义在于,它可以映射 m m m 的既约剩余系,而且每个元素一一对应。
比如我们在求 x a b <mtext>   </mtext> ( m o d <mtext>   </mtext> m ) x^a\equiv b~(mod~m) xab (mod m) m m m 是质数)时,我们可以设 g t x <mtext>   </mtext> ( m o d <mtext>   </mtext> m ) g^t\equiv x~(mod~m) gtx (mod m),其中 g g g m m m 的原根,不难证明这样的 t t t 一定存在。且一个 t t t 与一个 x x x 一一对应。
那么即是求 ( g t ) a ( g a ) t b <mtext>   </mtext> ( m o d <mtext>   </mtext> m ) (g^t)^a\equiv (g^{a})^t\equiv b~(mod~m) (gt)a(ga)tb (mod m) t t t。因为 g a g^a ga 已知,所以用 B S G S BSGS BSGS t t t 即可。
原根还在 N T T NTT NTT 中有着重要的作用。
于是学习原根其实是在为学 NTT 做铺垫。



原根存在的条件

m = 2 , 4 , p k , 2 p k m=2,4,p^k,2*p^k m=2,4,pk,2pk p p p 为奇素数)时, m m m 的原根存在。其余情况不存在原根。
证明的话,我不会证。。



如何求原根

因为原根密度很大,大约是 n 0.25 n^{0.25} n0.25,所以可以考虑暴力枚举找到一个原根。
当枚举到 a a a 时,如何快速判断 a a a 是不是原根呢?注意 a , m a,m a,m 要互质。
a a a 不是原根的条件是,存在 l < φ ( m ) l<\varphi(m) l<φ(m),使得 a l 1 <mtext>   </mtext> ( m o d <mtext>   </mtext> m ) a^l\equiv 1~(mod~m) al1 (mod m)
φ ( m ) = p i k i \varphi(m)=\prod p_i^{k_i} φ(m)=piki
由于 l l l φ ( m ) \varphi(m) φ(m) 的约数,所以我们预处理 φ ( m ) \varphi(m) φ(m) 的素因子,然后枚举素因子 p i p_i pi,判断是否 a φ ( m ) p i 1 <mtext>   </mtext> ( m o d <mtext>   </mtext> m ) a^{\frac{\varphi(m)}{p_i}} \equiv 1~(mod~m) apiφ(m)1 (mod m) 即可。
单次判断复杂度是 O ( l o g 2 n ) O(log^2n) O(log2n) 的。
这里有一道模板题

代码如下

#include <bits/stdc++.h>
#include<ext/pb_ds/hash_policy.hpp>
#include<ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
struct custom_hash {
	   static uint64_t splitmix64(uint64_t x) {
	   	x += 0x9e3779b97f4a7c15;
		x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
		x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
		return x ^ (x >> 31);
	}
	size_t operator()(uint64_t x) const {
		static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
		return splitmix64(x + FIXED_RANDOM);
	}
};
LL z = 1;
int read(){
	int x, f = 1;
	char ch;
	while(ch = getchar(), ch < '0' || ch > '9') if(ch == '-') f = -1;
	x = ch - '0';
	while(ch = getchar(), ch >= '0' && ch <= '9') x = x * 10 + ch - 48;
	return x * f;
}
int ksm(int a, int b, int p){
	int s = 1;
	while(b){
		if(b & 1) s = z * s * a % p;
		a = z * a * a % p;
		b >>= 1;
	}
	return s;
}
int phi(int x){
	int ret = x;
	for(int i = 2; i <= x / i; i++){
		if(x % i == 0){
			ret = ret / i * (i - 1);
			while(x % i == 0) x /= i;
		}
	}
	if(x > 1) ret = ret / x * (x - 1);
	return ret;
}
vector<int> d;
void get(int x){
	for(int i = 2; i <= x / i; i++){
		if(x % i == 0){
			d.push_back(i);
			while(x % i == 0) x /= i;
		}
	}
	if(x > 1) d.push_back(x);
}
int main(){
	int i, j, flag, n, p, m;
	p = read(); m = phi(p);
	get(m);
	for(i = 2; i <= p; i++){
		flag = 0;
		for(auto x: d){
			if(ksm(i, m / x, p) == 1){
				flag = 1;
				break;
			}
		}
		if(!flag){
			printf("%d", i);
			return 0;
		}
	}
	return 0;
}