数论之阶与原根讲解
前言:
本来想写BSGS算法,但是笔者今天想打游戏 感觉先写原根会更好一点,所以我们今天重点讨论一下什么是原根、哪些整数有原根、原根的性质和求解。
提要:
为了减少后面的阅读障碍,先简单介绍一下欧拉函数
φ
(
x
)
\varphi(x)
φ(x),主要部分后面放积性函数那介绍。(ps:书上符号写的是
ϕ
(
x
)
\phi(x)
ϕ(x),但网上写的是
φ
(
x
)
\varphi(x)
φ(x),不过这不重要)
欧拉函数
φ
(
x
)
\varphi(x)
φ(x)的函数值是,小于
x
x
x且与
x
x
x互质的正整数的个数。
比如
φ
(
6
)
=
2
\varphi(6)=2
φ(6)=2,因为小于
6
6
6的正整数中,仅有
1
1
1与
5
5
5与其互质。
容易发现,当
p
p
p为素数时,有
φ
(
x
)
=
p
−
1
\varphi(x)=p-1
φ(x)=p−1。
还有欧拉定理:若
g
c
d
(
a
,
n
)
=
1
gcd(a,n)=1
gcd(a,n)=1,则
a
φ
(
n
)
≡
1
(
m
o
d
p
)
a^{\varphi(n)}\equiv1(mod\;p)
aφ(n)≡1(modp)。
差不多先这些,开始正文。
整数的阶:
什么是阶?
设
a
a
a和
n
n
n是互素的整数,
a
≠
0
,
n
>
0
a\neq 0,n>0
a=0,n>0,使得
a
x
≡
1
(
m
o
d
n
)
a^{x}\equiv1(mod\;n)
ax≡1(modn)成立的最小正整数
x
x
x,称为
a
a
a模
n
n
n的阶,符号表示为
o
r
d
n
a
ord_{n}a
ordna。
比如要求
2
2
2模
7
7
7的阶,我们一一列举,
2
1
≡
2
(
m
o
d
7
)
,
2
2
≡
4
(
m
o
d
7
)
,
2
3
≡
1
(
m
o
d
7
)
2^{1}\equiv2(mod\;7),2^{2}\equiv4(mod\;7),2^{3}\equiv1(mod\;7)
21≡2(mod7),22≡4(mod7),23≡1(mod7)。
那么我们称
2
2
2模
7
7
7的阶就是
3
3
3,记为
o
r
d
7
2
=
3
ord_{7}2=3
ord72=3。
现在我们观察方程
a
x
≡
1
(
m
o
d
n
)
a^{x}\equiv1(mod\;n)
ax≡1(modn)。
那么显然根据欧拉定理,我们可以知道
φ
(
n
)
\varphi(n)
φ(n)是方程的一个解,但它未必是最小的,所以不一定是阶,而当
φ
(
n
)
\varphi(n)
φ(n)是
a
a
a模
n
n
n的阶时,我们称
a
a
a为
n
n
n的一个原根,这个放后面介绍。
现在继续来讲阶。
定理一:若
g
c
d
(
a
,
n
)
=
1
gcd(a,n)=1
gcd(a,n)=1,则
x
0
x_{0}
x0是方程
a
x
≡
1
(
m
o
d
n
)
a^{x}\equiv1(mod\;n)
ax≡1(modn)的一个解的充要条件是
o
r
d
n
a
∣
x
ord_{n}a|x
ordna∣x。(其中
∣
|
∣是整除符号,表示
o
r
d
n
a
ord_{n}a
ordna整除
x
x
x)
这个必要性很好证明,既然
a
o
r
d
n
a
≡
1
(
m
o
d
n
)
a^{ord_{n}a}\equiv1(mod\;n)
aordna≡1(modn),那
a
k
×
o
r
d
n
a
≡
1
(
m
o
d
n
)
a^{k\times ord_{n}a}\equiv1(mod\;n)
ak×ordna≡1(modn)当然也成立。
然后充分性,假设存在
x
1
x1
x1不整除
x
0
x_{0}
x0且满足方程,令
x
1
=
k
×
o
r
d
n
a
+
d
x_{1}=k\times ord_{n}a+d
x1=k×ordna+d(其中
d
d
d不整除
o
r
d
n
a
ord_{n}a
ordna)满足方程,那么
d
d
d一定比
o
r
d
n
a
ord_{n}a
ordna小,且满足
a
d
≡
1
(
m
o
d
n
)
a^{d}\equiv1(mod\;n)
ad≡1(modn),那它才是原根嘛。
这样就证好了。
定理二:若
g
c
d
(
a
,
n
)
=
1
gcd(a,n)=1
gcd(a,n)=1,则
o
r
d
n
a
ord_{n}a
ordna能整除
φ
(
n
)
\varphi(n)
φ(n)。
前面看下来应该也能想到,且由定理一发现显然嘛。
这时候我们容易想到一个
o
(
n
l
o
g
)
o(\sqrt{n} log)
o(nlog)求阶的办法,因为
n
n
n的阶一定是
φ
(
n
)
\varphi(n)
φ(n)的因子,所以可以暴力枚举其因子,再看看是不是满足条件。
定理三:若
g
c
d
(
a
,
n
)
=
1
gcd(a,n)=1
gcd(a,n)=1,则
a
i
≡
a
j
(
m
o
d
n
)
a^i\equiv a^j(mod\;n)
ai≡aj(modn)的充要条件是
i
≡
j
(
m
o
d
o
r
d
n
a
)
i\equiv j(mod\;ord_{n}a)
i≡j(modordna)。
定理比较重要,自己意会一下。
定理四:若
o
r
d
n
a
=
t
ord_{n}a=t
ordna=t,且
u
u
u为正整数,则有
o
r
d
n
(
a
u
)
=
t
g
c
d
(
t
,
u
)
ord_{n}(a^{u})=\frac{t}{gcd(t,u)}
ordn(au)=gcd(t,u)t 。
打个比方体会一下,
2
3
≡
1
(
m
o
d
7
)
2^3\equiv1(mod\;7)
23≡1(mod7),那么就有
8
1
≡
1
(
m
o
d
7
)
8^1\equiv1(mod\;7)
81≡1(mod7)。其实就是这个
3
3
3的因子,这样想就容易理解多了吧。
原根:
当
a
a
a模
n
n
n的阶为
φ
(
n
)
\varphi(n)
φ(n),也就是说当且仅当
x
x
x是
φ
(
n
)
\varphi(n)
φ(n)的倍数,使得
a
x
≡
1
(
m
o
d
n
)
a^{x}\equiv1(mod\;n)
ax≡1(modn)成立,此时称
a
a
a为
n
n
n的原根。
那么知道了
n
n
n的原根
a
a
a后,有什么好处呢,可以举一个例子。
我们举998244353的原根3, 我们举一个素数
7
7
7的一个原根
3
3
3,然后列举
3
3
3的幂次模
7
7
7。
3
1
≡
3
(
m
o
d
7
)
,
3
2
≡
2
(
m
o
d
7
)
,
3
3
≡
6
(
m
o
d
7
)
,
3
4
≡
4
(
m
o
d
7
)
,
3
5
≡
5
(
m
o
d
7
)
,
3
6
≡
1
(
m
o
d
7
)
3^{1}\equiv3(mod\;7),3^{2}\equiv2(mod\;7),3^{3}\equiv6(mod\;7),3^{4}\equiv4(mod\;7),3^{5}\equiv5(mod\;7),3^{6}\equiv1(mod\;7)
31≡3(mod7),32≡2(mod7),33≡6(mod7),34≡4(mod7),35≡5(mod7),36≡1(mod7)。
然后发现这些余数构成了一个模
7
7
7的完全剩余系
1
,
2
,
3
,
4
,
5
,
6
1,2,3,4,5,6
1,2,3,4,5,6,也就是对于任意
a
a
a,都可以找到
x
0
x_{0}
x0使得
3
x
0
≡
a
(
m
o
d
7
)
3^{x_{0}}\equiv a(mod\;7)
3x0≡a(mod7)。
这是素数的情况,现在我们来康康非素数的情况,举
18
18
18的一个原根
5
5
5。然后列举
5
5
5的幂次模
18
18
18。
5
1
≡
5
(
m
o
d
18
)
,
5^{1}\equiv5(mod\;18),
51≡5(mod18),
5
2
≡
7
(
m
o
d
18
)
,
5^{2}\equiv7(mod\;18),
52≡7(mod18),
5
3
≡
17
(
m
o
d
18
)
,
5^{3}\equiv17(mod\;18),
53≡17(mod18),
5
4
≡
13
(
m
o
d
18
)
,
5^{4}\equiv13(mod\;18),
54≡13(mod18),
5
5
≡
11
(
m
o
d
18
)
,
5^{5}\equiv11(mod\;18),
55≡11(mod18),
5
6
≡
1
(
m
o
d
18
)
。
5^{6}\equiv1(mod\;18)。
56≡1(mod18)。
5
7
≡
5
(
m
o
d
18
)
,
5^{7}\equiv5(mod\;18),
57≡5(mod18),
5
8
≡
7
(
m
o
d
18
)
,
5^{8}\equiv7(mod\;18),
58≡7(mod18),
5
9
≡
17
(
m
o
d
18
)
,
5^{9}\equiv17(mod\;18),
59≡17(mod18),
5
10
≡
13
(
m
o
d
18
)
,
5^{10}\equiv13(mod\;18),
510≡13(mod18),
5
11
≡
11
(
m
o
d
18
)
,
5^{11}\equiv11(mod\;18),
511≡11(mod18),
5
12
≡
1
(
m
o
d
18
)
。
5^{12}\equiv1(mod\;18)。
512≡1(mod18)。
5
13
≡
5
(
m
o
d
18
)
,
5^{13}\equiv5(mod\;18),
513≡5(mod18),
5
14
≡
7
(
m
o
d
18
)
,
5^{14}\equiv7(mod\;18),
514≡7(mod18),
5
15
≡
17
(
m
o
d
18
)
,
5^{15}\equiv17(mod\;18),
515≡17(mod18),
5
16
≡
13
(
m
o
d
18
)
,
5^{16}\equiv13(mod\;18),
516≡13(mod18),
5
17
≡
11
(
m
o
d
18
)
,
5^{17}\equiv11(mod\;18),
517≡11(mod18),
5
18
≡
1
(
m
o
d
18
)
。
5^{18}\equiv1(mod\;18)。
518≡1(mod18)。
很容易发现以
6
6
6个为一组,那这个
6
6
6是什么呢?
其实是
φ
(
18
)
=
6
\varphi(18)=6
φ(18)=6。然后出现的数字
1
,
5
,
7
,
11
,
13
,
17
1,5,7,11,13,17
1,5,7,11,13,17,正是与
18
18
18互质的那
6
6
6个数啊。
那么前面素数的情况也说得通了。
所以我们就可以得到,
定理一:若
g
c
d
(
a
,
n
)
=
1
gcd(a,n)=1
gcd(a,n)=1,则
a
1
,
a
2
,
…
…
,
a
φ
(
n
)
a^{1},a^{2},……,a^{\varphi(n)}
a1,a2,……,aφ(n)构成模
n
n
n的既约剩余系。
大概懂了就不证明了。
而当
p
p
p为素数时,我们就可以将求解方程
x
5
≡
a
(
m
o
d
p
)
x^{5}\equiv a(mod\;p)
x5≡a(modp)的问题代换为求解
g
5
x
≡
a
(
m
o
d
p
)
g^{5x}\equiv a(mod\;p)
g5x≡a(modp),其中
g
g
g是
p
p
p的原根,因为
g
g
g的幂次是模
n
n
n的完全剩余系,所以可以用
g
x
g^{x}
gx来代换
x
x
x,这样我们只要求出新方程的
x
0
x_{0}
x0,那么原方程的解就可以求出来了。
下一个,
定理二:如果一个数
n
n
n有原根,那么他有多少个不同余的原根,
答案是
φ
(
φ
(
n
)
)
\varphi(\varphi(n))
φ(φ(n))个。
伪证明:由前面阶那里的定理四,我们可以知道
o
r
d
n
(
a
u
)
=
t
g
c
d
(
t
,
u
)
ord_{n}(a^{u})=\frac{t}{gcd(t,u)}
ordn(au)=gcd(t,u)t,那么当
a
a
a为
n
n
n的原根时,就有
o
r
d
n
a
=
φ
(
n
)
ord_{n}a=\varphi(n)
ordna=φ(n)。
于是我们得到,
o
r
d
n
(
a
u
)
=
φ
(
n
)
g
c
d
(
φ
(
n
)
,
u
)
ord_{n}(a^{u})=\frac{\varphi(n)}{gcd(\varphi(n),u)}
ordn(au)=gcd(φ(n),u)φ(n)。
所以要使
o
r
d
n
(
a
u
)
ord_{n}(a^{u})
ordn(au)等于
φ
(
n
)
\varphi(n)
φ(n),就要满足
g
c
d
(
φ
(
n
)
,
u
)
gcd(\varphi(n),u)
gcd(φ(n),u),在
1
1
1到
φ
(
n
)
−
1
\varphi(n)-1
φ(n)−1范围里自然就有
φ
(
φ
(
n
)
)
\varphi(\varphi(n))
φ(φ(n))个满足条件的。
吃饭去了,回来再写。
现在研究哪些数是有原根的,也就是原根的存在性。
因为刚吃了饭,我懒了。
先证明素数都是有原根的。
再证明奇素数的幂都是有原根的。
然后讨论关于
2
2
2的幂次,发现
2
2
2和
4
4
4是有原根的,其他
2
2
2的幂次都没有原根。
然后再发现
2
2
2乘上奇素数的幂也是有原根的。
最后再证明剩下的都没有原根。
于是,得出结论:
定理三:
2
2
2和
4
4
4,和奇素数的正整数幂次
p
k
p^{k}
pk,以及
2
2
2乘上奇素数的正整数幂次
2
p
k
2p^{k}
2pk都是有原根的。
最后,再研究一下怎么求
p
p
p的原根。传送门
先给出一种暴力的解法。(没有第二种了)
先判断有无原根。
2
2
2的原根是
1
1
1,
3
3
3的原根是2,
4
4
4的原根是
3
3
3直接特判掉。
然后我们暴力枚举
[
2
,
p
−
1
]
[2,p-1]
[2,p−1],再判断它是不是
p
p
p的原根,枚举的时候当然还要保证与模数互质。
至于要判断
i
i
i是不是
p
p
p的原根,只要看是否存在
x
0
x_{0}
x0比
φ
(
p
)
\varphi(p)
φ(p)小,且满足
i
x
0
≡
1
(
m
o
d
p
)
i^{x_{0}}\equiv 1(mod\;p)
ix0≡1(modp)。
但是我们不至于再去一个一个枚举
x
0
x_{0}
x0,因为我们知道它的阶是满足方程的,而阶的倍数也是满足方程的。所以我们只要将
φ
(
p
)
\varphi(p)
φ(p)质因子分解成
p
1
k
1
p
2
k
2
…
p
n
k
n
p_{1}^{k_{1}}p_{2}^{k_{2}}…p_{n}^{k_{n}}
p1k1p2k2…pnkn。
然后枚举每个质因子,判断是否存在
i
φ
(
p
)
p
j
≡
1
(
m
o
d
p
)
i^{\frac{\varphi(p)}{p_{j}}}\equiv1(mod\;p)
ipjφ(p)≡1(modp)。若存在,说明阶比
φ
(
p
)
\varphi(p)
φ(p)小,则不是原根;反之,则是原根。
大力出奇迹,不愧是大力。
最后贴代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll gcd(ll a,ll b)
{
return b?gcd(b,a%b):a;
}
ll fpow(ll a,ll n,ll p)
{
ll sum=1,base=a%p;
while(n!=0)
{
if(n%2)sum=sum*base%p;
base=base*base%p;
n/=2;
}
return sum;
}
vector<ll> getPrimFac(ll n)
{
vector<ll>fac;
fac.clear();
for(ll i=2;i*i<=n;i++)
{
if(n%i==0)
{
fac.push_back(i);
while(n%i==0)n/=i;
}
}
if(n>1)fac.push_back(n);
return fac;
}
bool hasRoot(ll n)
{
if(n==2||n==4)return true;
if(n<=1||n%4==0)return false;
ll num=0;
while(n%2==0)n/=2;
for(ll i=3;i*i<=n;i++)
{
if(n%i==0)
{
num++;
while(n%i==0)n/=i;
}
}
if(n>1)num++;
if(num==1)return true;
return false;
}
ll getPhi(ll n)
{
ll ans=n;
for(ll i=2;i*i<=n;i++)
{
if(n%i==0)
{
ans=ans/i*(i-1);
while(n%i==0)n/=i;
}
}
if(n>1)ans=ans/n*(n-1);
return ans;
}
ll getRoot(ll n)
{
if(!hasRoot(n))return -1;//不存在原根返回-1
if(n==2)return 1;
if(n==3)return 2;
if(n==4)return 3;
ll w=getPhi(n);
vector<ll>fac=getPrimFac(w);
for(ll i=2;i<w;i++)
{
if(gcd(i,n)!=1)continue;
ll is=1;
for(ll j=0;j<fac.size();j++)
{
if(fpow(i,w/fac[j],n)==1)is=0;
}
if(is)return i;
}
return -1;
}
int main()
{
ll p;
scanf("%lld",&p);
printf("%lld\n",getRoot(p));
return 0;
}