设正整数
n
>
1
n>1
n>1,
a
a
a 是满足
a
⊥
n
a\perp n
a⊥n (
a
a
a 与
n
n
n 互质)的整数,则必有一个正整数
r
∈
[
1
,
n
]
r\in [1,n]
r∈[1,n],使得
a
r
≡
1
(
m
o
d
n
)
a^r\equiv 1(mod~n)
ar≡1(modn)。
满足条件的最小的正整数
r
r
r,称为
a
a
a 模
n
n
n 的阶,记作
O
r
d
n
(
a
)
Ord_n(a)
Ordn(a)。
注意,若
(
a
,
n
)
≠
1
(a,n)\neq 1
(a,n)̸=1,则不存在
a
a
a 模
n
n
n 的阶。
1.2 阶的性质
设
a
⊥
n
a\perp n
a⊥n,
a
N
≡
1
(
m
o
d
n
)
⇔
O
r
d
n
(
a
)
∣
N
a^N\equiv 1(mod~n) \Leftrightarrow Ord_n(a)|N
aN≡1(modn)⇔Ordn(a)∣N。
设
a
⊥
n
a\perp n
a⊥n,
O
r
d
n
(
a
)
∣
φ
(
n
)
Ord_n(a)|\varphi(n)
Ordn(a)∣φ(n)。
2. 原根
2.1 定义
设正整数
n
>
1
n>1
n>1,
a
a
a 是满足
a
⊥
n
a\perp n
a⊥n 的整数,若
O
r
d
n
(
a
)
=
φ
(
n
)
Ord_n(a)=\varphi(n)
Ordn(a)=φ(n),则称
a
a
a 为模
n
n
n 的一个原根。
2.2 解性
设正整数
n
>
1
n>1
n>1,
n
n
n 的原根是一些关于
n
n
n 的剩余类(原根可以不止一个)。
所以研究原根时,我们只需要研究
[
1
,
n
)
[1,n)
[1,n) 范围内的解即可。
2.3 原根的性质
只有
2
,
4
,
p
k
,
2
p
k
(
p
是
奇
素
数
)
2,4,p^k,2p^k(p是奇素数)
2,4,pk,2pk(p是奇素数) 有原根。
一个数
n
n
n 若存在原根,则它有
φ
(
φ
(
n
)
)
\varphi(\varphi(n))
φ(φ(n)) 个原根。
记
δ
=
O
r
d
n
(
a
)
\delta=Ord_n(a)
δ=Ordn(a),则
a
0
,
a
1
,
…
,
a
δ
−
1
a^0,a^1,\dots,a^{\delta-1}
a0,a1,…,aδ−1 模
n
n
n 两两不同余,当
a
a
a 是
n
n
n 的原根时,
a
0
,
a
1
,
…
,
a
δ
−
1
a^0,a^1,\dots,a^{\delta-1}
a0,a1,…,aδ−1 构成模
n
n
n 的简化剩余系。特别地,当
n
n
n 是质数时,
a
0
,
a
1
,
…
,
a
δ
−
1
a^0,a^1,\dots,a^{\delta-1}
a0,a1,…,aδ−1 对
n
n
n 取模后对应为
{
1
,
2
,
…
,
n
−
1
}
\{1,2,\dots,n-1\}
{1,2,…,n−1}。
2.4 求一个数原根的方法
我们已知一个数
n
n
n 存在原根。
我们现在要找到
n
n
n 最小的原根。
假设我们现在枚举到一个
g
g
g,并且
(
g
,
n
)
=
1
(g,n)=1
(g,n)=1,要验证
g
g
g 是否是
n
n
n 的原根。
根据
O
r
d
n
(
g
)
∣
φ
(
n
)
Ord_n(g)|\varphi(n)
Ordn(g)∣φ(n),我们只需要验证对于每个
d
∣
φ
(
n
)
(
d
≠
φ
(
n
)
)
d|\varphi(n)(d\neq \varphi(n))
d∣φ(n)(d̸=φ(n)),是否均满足
g
d
̸
≡
1
(
m
o
d
n
)
g^d\not\equiv 1(mod~n)
gd̸≡1(modn)。
我们设
φ
(
n
)
=
∏
i
=
1
c
p
i
k
i
\varphi(n)=\prod_{i=1}^cp_i^{k_i}
φ(n)=∏i=1cpiki(
p
i
p_i
pi 是质数)。
因为若
g
d
≡
1
(
m
o
d
n
)
g^d\equiv 1(mod~n)
gd≡1(modn),则
g
d
k
≡
1
(
m
o
d
n
)
g^{dk}\equiv 1(mod~n)
gdk≡1(modn),所以我们只需要验证,对于每个
i
i
i,均满足
g
n
p
i
̸
≡
1
(
m
o
d
n
)
g^{\frac{n}{p_i}}\not\equiv1(mod~n)
gpin̸≡1(modn) 即可。
只需要暴力枚举验证即可。
最小原根的范围都很小。
//mod是指需要求mod的最小原根,phi是mod的phi函数值inlineintfind_root(constint&mod,constint&phi){staticint p[MaxCnt];staticint cnt;
cnt =0;int x = phi;for(int i =2; i * i <= phi;++i)if(x % i ==0){
p[++cnt]= i;while(x % i ==0)
x /= i;}if(x >1)
p[++cnt]= x;for(int g =1; g <= mod;++g){if(std::__gcd(g, mod)>1)continue;bool flg =true;for(int i =1; i <= cnt;++i)if(qpow(g, phi / p[i], mod)==1){
flg =false;break;}if(flg)return g;}return-1;}
3. 指标
3.1 定义
设
g
g
g 是
n
n
n 的一个原根,整数
a
⊥
n
a \perp n
a⊥n,则在模
φ
(
n
)
\varphi(n)
φ(n) 意义下有唯一的整数
x
x
x,使得
g
x
≡
a
(
m
o
d
n
)
g^x\equiv a(mod~n)
gx≡a(modn),则称
x
x
x 为以
g
g
g 为底对模
n
n
n 的一个指标,记作
x
=
i
n
d
g
a
x=ind_ga
x=indga。
3.2 指标的性质
a
≡
b
(
m
o
d
p
)
⇔
i
n
d
g
a
≡
i
n
d
g
b
(
m
o
d
φ
(
p
)
)
a\equiv b~(mod~p)\Leftrightarrow ind_ga\equiv ind_gb~(mod~\varphi(p))
a≡b(modp)⇔indga≡indgb(modφ(p))
i
n
d
g
(
a
b
)
≡
i
n
d
(
a
)
+
i
n
d
(
b
)
(
m
o
d
φ
(
p
)
)
ind_g(ab)\equiv ind(a)+ind(b)~(mod~\varphi(p))
indg(ab)≡ind(a)+ind(b)(modφ(p))
i
n
d
g
(
a
n
)
≡
n
×
i
n
d
(
a
)
(
m
o
d
φ
(
p
)
)
ind_g(a^n)\equiv n\times ind(a)~(mod~\varphi(p))
indg(an)≡n×ind(a)(modφ(p))
3.3 求指标的方法
求指标的运算也叫做离散对数。
求指标即求
g
x
≡
a
(
m
o
d
p
)
g^x\equiv a(mod~p)
gx≡a(modp) 的最小自然数解。
使用
B
S
G
S
BSGS
BSGS 算法即可。
4. N次剩余问题
问题:求解
x
N
≡
a
(
m
o
d
p
)
x^N\equiv a(mod~p)
xN≡a(modp) 在模
p
p
p 意义下的所有解,
p
p
p 是质数。
首先我们知道,当
a
≡
0
(
m
o
d
p
)
a\equiv 0(mod~p)
a≡0(modp) 时,方程只有
x
=
0
x=0
x=0 一个解。
否则
x
∈
[
1
,
p
)
x\in[1,p)
x∈[1,p)。
我们先找到
p
p
p 的最小原根
g
g
g。
因为
p
p
p 是质数且
p
∤
a
p\nmid a
p∤a,所以每个
x
∈
[
1
,
p
)
x\in[1,p)
x∈[1,p),我们都能找到
y
=
i
n
d
g
x
y=ind_gx
y=indgx 和
t
=
i
n
d
g
a
t=ind_ga
t=indga。
那么原方程等价于
y
N
≡
t
(
m
o
d
(
p
−
1
)
)
yN\equiv t(mod~(p-1))
yN≡t(mod(p−1))。
那么我们只需要用
e
x
g
c
d
exgcd
exgcd 解这个简单的同余方程即可。
当
(
N
,
p
−
1
)
∤
t
(N,p-1)\nmid t
(N,p−1)∤t 时,原方程无解。
否则我们求出最小自然数解
y
0
y_0
y0,然后将在
[
1
,
p
)
[1,p)
[1,p) 内的
y
=
y
0
+
k
⋅
p
−
1
(
N
,
p
−
1
)
(
k
∈
Z
)
y=y_0+k·\frac{p-1}{(N,p-1)}(k\in \mathbb Z)
y=y0+k⋅(N,p−1)p−1(k∈Z) 的
y
y
y 记录下来。
#include<bits/stdc++.h>int p, K, a, g, t;int anscnt, ans[1000010];inlineintqpow(int a,int b,constint&p){int res =1;for(; b; b >>=1, a =1LL* a * a % p)if(b &1)
res =1LL* res * a % p;return res;}inlineintfind_root(constint&p){int n = p -1, x = p -1;staticint div[1000010], cnt;
cnt =0;for(int i =2; i * i <= n;++i)if(x % i ==0){
div[++cnt]= i;while(x % i ==0)
x /= i;}if(x >1)
div[++cnt]= x;for(int g =1; g <= p;++g){bool flg =true;for(int i =1; i <= cnt;++i)if(qpow(g,(p -1)/ div[i], p)==1){
flg =false;break;}if(flg)return g;}return-1;}inlineintsolve_BSGS(constint&a,constint&b,constint&p){
std::map<int,int> ha;
ha.clear();int t =ceil(sqrt(p)), x =1;for(int i =1; i <= t;++i){
x =1LL* x * a % p;
ha[1LL* x * b % p]= i;}int y = x;for(int i =1; i <= t;++i){if(ha.find(y)!= ha.end())return i * t - ha[y];
y =1LL* y * x % p;}return-1;}inlineintexgcd(constint&a,constint&b,int&x,int&y){if(!b)return x =1, y =0, a;int res =exgcd(b, a % b, y, x);
y -= a / b * x;return res;}intmain(){scanf("%d%d%d",&p,&K,&a);if(a ==0)returnputs("1\n0"),0;
g =find_root(p);
t =solve_BSGS(g, a, p);int x, y;int d =exgcd(p -1, K, x, y);if(t % d)returnputs("0"),0;int mod =(p -1)/ d;
y =(1LL* y *(t / d)% mod + mod)% mod;for(; y < p; y += mod)
ans[++anscnt]=qpow(g, y, p);
std::sort(ans +1, ans + anscnt +1);printf("%d\n", anscnt);for(int i =1; i <= anscnt;++i)printf("%d\n", ans[i]);return0;}