本文中,若无特殊说明,mm 代表正整数,pp 代表质数。

事实上,在题目中我们大多数情况下都是讨论对质数取模的情况。

定义

(a,m)=1(a,m)=1,满足 an=1(modm)a^n = 1 \pmod m 的最小的 nn 称为 aamm 的阶,记作 δma\delta_m a

如果 (a,m)=1(a,m)=1 不互质,那么不难发现,不存在 nn,使得 an=1(modm)a^n = 1 \pmod m,故我们不定义 aamm 的阶。

性质

本节中 a,ba,b 均与 mm 互质。

  1. a,a2,,aδmaa,a^2,\ldots,a^{\delta_m a}mm 两两不同。

    【引理 1】完全剩余系中与 mm 互质的剩余类所构成的系称为缩系,缩系内四则运算均封闭。
    (证明略)

    性质 1 证明:
    用反证法,假设存在 1i<jδma1\le i < j \le \delta_m a,使得 aiaj(modm)a^i \equiv a^j \pmod m,因为 aia^iaja^j 均与 mm 互质,存在逆元,故 aji1(modm)a ^{j-i} \equiv 1 \pmod m,而 ji<δmaj-i < \delta_m a,故 δma\delta_m a 不是最小,矛盾!

  2. an1(modm)    n0(modδma)a^n \equiv 1 \pmod m \iff n\equiv 0\pmod {\delta_m a }

    【引理 2】若 axay1(modm)a^x \equiv a^y \equiv 1 \pmod m,则 agcd(x,y)1(modm)a^{\gcd(x,y)}\equiv 1 \pmod m
    【引理 2 证明】因为存在逆元,我们可知 aAx+By1(modm) (A,BZ)a^{Ax+By}\equiv 1 \pmod m\ (A,B\in\Z)。由裴蜀定理,gcd(x,y)\gcd(x,y) 能表示为 x,yx,y 的线性组合,故引理成立。

    性质 2 证明:
    先证 \Leftarrow:若 n0(modδma)n\equiv 0\pmod {\delta_m a },设 n=kδma (kN)n=k\delta_m a\ (k\in \N^{*})an=(aδma)k1(modm)a^n = \left(a^{\delta_m a}\right)^{k}\equiv 1\pmod m
    再证 \Rightarrow:用反证法,假设存在 an1a^n \equiv 1nn 不是 δma\delta_m a 的倍数,则 gcd(n,δma)\gcd(n,\delta_m a),由引理 2 可知 agcd(n,δma)1(modm)a^{\gcd(n,\delta_m a)}\equiv 1 \pmod m,故 δma\delta_m a 不是最小,矛盾!

  3. axay(modm)    xy(modδma)a^x\equiv a^y \pmod m \iff x \equiv y \pmod {\delta_m a}

    性质 3 证明:
    先证 \Leftarrow:若 xy(modδma)x \equiv y \pmod {\delta_m a},则 axy1(modm)a^{x-y} \equiv 1 \pmod m,则 axay(modm)a^x \equiv a^y \pmod m
    再证 \Rightarrow:因为 axy1(modm)a^{x-y}\equiv 1\pmod m,由性质 2 可知,xyx-yδma\delta_m a 的倍数,故成立。

  4. δm(ab)=δmaδmb    (δma,δmb)=1\delta_m (ab) = \delta_m a \delta_m b \iff (\delta_m a,\delta_m b)=1

    性质 4 证明:

    • 先证 \Rightarrow
      因为 aδma1(modm)a^{\delta_m a}\equiv 1\pmod mbδmb1(modm)b^{\delta_m b}\equiv 1\pmod m,故 ab[δma,δmb]1(modm)ab^{[\delta_m a,\delta_m b]}\equiv 1\pmod m
      由性质 2 可知,δm(ab)[δma,δmb]\delta_m(ab)\mid [\delta_m a,\delta_m b],即 δmaδmb[δma,δmb]\delta_m a \delta_m b \mid [\delta_m a,\delta_m b]
      (δma,δmb)=1(\delta_m a,\delta_m b)=1

    • 再证 \Leftarrow
      因为 aδma1(modm)a^{\delta_m a}\equiv 1\pmod mbδmb1(modm)b^{\delta_m b}\equiv 1\pmod m,故 abδmaδmb1(modm)ab^{\delta_m a\delta_m b}\equiv 1\pmod m,即 δmaδmbδm(ab) ()\delta_m a\delta_m b\mid \delta_m(ab)\ (*)

      1(ab)δm(ab)δmb(a)δm(ab)δmb(modm)1\equiv(ab)^{\delta_m(ab)\delta_m b}\equiv(a)^{\delta_m(ab)\delta_m b}\pmod m,可知 δmaδm(ab)δmb\delta_m a \mid \delta_m(ab)\delta_m b
      结合 (δma,δmb)=1(\delta_m a,\delta_m b)=1,得 δmaδm(ab)\delta_m a \mid \delta_m(ab)
      同理 δmbδm(ab)\delta_m b \mid \delta_m(ab),故 δmaδmbδm(ab) ()\delta_m a\delta_m b \mid \delta_m(ab)\ (\triangle)

      (),()(*),(\triangle) 两式得 δm(ab)=δmaδmb\delta_m (ab) = \delta_m a \delta_m b

  5. δm(ak)=δma(δma,k)\delta _m(a^k) = \dfrac{\delta_m a}{(\delta_m a,k)}

    性质 5 证明:
    δm(ak)=d\delta _m(a^k)=d,有 (ak)d1(modm)\left(a^k\right)^d\equiv 1\pmod m
    即要找到最小的 dd 满足 akd1(modm)a^{kd}\equiv 1\pmod m
    由性质 2 可知,我们需要让 kd0(modδma)kd \equiv 0\pmod {\delta_m a }
    不难发现最小的 dd 即为 δma(δma,k)\dfrac{\delta_m a}{(\delta_m a,k)}

求法

如果求 aa 的阶(aamm 互质),初始令阶 xxφ(m)\varphi(m),对 φ(m)\varphi(m) 的每一个质因数,如果除了它之后仍然有 ax1(modm)a^x \equiv 1 \pmod m,则不断除掉这个质因数,最后得到的就是它的阶。

正确性说明:
假设最后结果为 dd

显然有 ad1(modm)a^d\equiv 1\pmod m,只需证明不存在更小的 xx 使得 ax1(modm)a^x\equiv 1\pmod m 即可。
如果 δmad\delta_m a\ne d,则存在 fdf\mid dad/f1(modm)a^{d/f}\equiv 1\pmod m,显然与我们的算法矛盾,故该算法能正确求出阶。

复杂度 O(m+log2m)O(\sqrt m +\log^2 m)。(预处理质因数 m\sqrt m,有 logm\log m 个质因数,每次快速幂判断复杂度为 logm\log m).

参考代码:

1
2
ll ord = phi(m);
for(auto f:fp)while(ord%f==0 && ksm(a,ord/f,m)==1)ord/=f;

其中 fp 是存有 φ(m)\varphi(m) 的质因数的 vector,函数 ksm(a,b,p) 表示 abmodma^b \bmod m 的值。

原根

原根和阶是紧密相关的概念。

定义

δm(g)=φ(m)\delta_m(g) = \varphi(m),称 gg 为模 mm 的原根。

性质

  1. (原根判定定理)g 是 m的原根    pφ(m),gφ(m)g≢1(modm) 且 (g,m)=1g \text{ 是 } m \text{的原根} \iff \forall p \mid \varphi(m),g^{\frac{\varphi(m)}{g}}\not \equiv 1 \pmod m \text{ 且 } (g,m)=1

    证明:
    与阶的求法正确性等价,读者自证不难。

  2. (原根个数定理)若 mm 存在一个原根 gg,则所有原根可以表示为 gkg^k,其中 (k,φ(m))=1(k,\varphi(m))=1。故原根个数有 φ(φ(m))\varphi(\varphi(m))个。

    证明:
    运用阶的性质 5 易证,留作读者练习。

  3. (原根存在定理)mm 存在原根当且仅当 m=2,4m=2,4m=pα,2pαm=p^\alpha, 2p^\alpha,其中
    pp 为质数,αN\alpha\in \N^*

  4. 若一个质数 pp 存在原根,其最小原根 gmin=O(p1/4)g_{\text{min}}=O(p^{1/4})。(这并不意味着存在一个小于等于 p1/4p^{1/4} 的原根)

求法

  1. 判断原根是否存在;O(n)O\left(\sqrt n\right) (或预处理 O(n)O(n)
  2. 若存在,从 11 开始枚举与 nn 互质的数,找到最小原根;O(n0.25log2n)O\left(n^{0.25} \log^2 n\right)
  3. 找出所有与 φ(n)\varphi(n) 互质的 kk,求出所有原根。O(φ(n)logφ(n))O(\varphi(n)\log\varphi(n))
  4. (对所有原根排序. O(φ(φ(n))logφ(φ(n)))O(\varphi(\varphi(n))\log\varphi(\varphi(n)))

参考代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include<bits/stdc++.h>
using namespace std;

using ll=long long;
inline int read(){int f=1,x=0;char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)){x=x*10+c-'0';c=getchar();}return x*f;}

const int N = 1e6+5;
bool vis[N];
int pri[N],cnt,phi[N];
bool have[N];

int ksm(int a,int b,int p){
int r = 1;
while(b){
if(b&1)r=(ll)r*a%p;
a=(ll)a*a%p;
b>>=1;
}
return r;
}

int main(){
// 线性筛预处理出素数和欧拉函数
phi[1]=1;
for(int i=2;i<N;i++){
if(!vis[i])pri[cnt++]=i,phi[i]=i-1;
for(int j=0;j<cnt&&i*pri[j]<N;j++){
vis[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);
}
}


have[2]=have[4]=1; // 2,4
for(int i=1;i<cnt;i++){
for(ll j=pri[i];j<N;j*=pri[i])have[j]=1; // p^a
for(ll j=2*pri[i];j<N;j*=pri[i])have[j]=1; // 2p^a
}

int T=read();
while(T--){
int n=read(),d=read();
if(!have[n]){ // 没有原根
puts("0\n");
continue;
}

vector<int> fac; // 求出φ(n)的质因数
int P = phi[n];
for(int i=2;i*i<=P;i++){
if(P%i==0){
fac.push_back(i);
while(P%i==0)P/=i;
}
}
if(P!=1)fac.push_back(P);
vector<int> g;
for(int i=1;;i++){
if(__gcd(n,i)!=1)continue; // i 与 n 互质
bool ok = 1;
for(auto p:fac)
if(ksm(i,phi[n]/p,n)==1){ok=0;break;}

if(ok){
for(int k=1;k<=phi[n];k++)
// 找到所有原根
if(__gcd(k,phi[n])==1)g.push_back(ksm(i,k,n));
break;
}
}

sort(g.begin(),g.end());
assert(g.size()==phi[phi[n]]);
printf("%d\n",(int)g.size());
for(int i=d-1;i<g.size();i+=d)printf("%d ",g[i]);
puts("");
}

return 0;
}

离散对数

定义

(a,m)=1(a,m)=1 时,若存在 akb(modm)a^k\equiv b\pmod m,则将满足上式的最小自然数 kk 称作对 mm 取模下,以 aa 为底 bb 的离散对数,记作indab=k\operatorname{ind} _a b = k

这就允许我们将模意义下的乘法化为加法,从而更方便的解决问题。

性质

  1. inda1=0\operatorname{ind} _a 1 = 0
  2. indaa=1\operatorname{ind} _a a = 1
  3. inda(xy)=indax+inday(modδma)\operatorname{ind}_a (xy) = \operatorname{ind}_a x + \operatorname{ind}_a y \pmod {\delta_m a}indaxnnindax(modδma)\operatorname{ind}_a x^n \equiv n \operatorname{ind}_a x \pmod {\delta_m a}
  4. xy(modm)    indax=indayx\equiv y \pmod m \iff \operatorname{ind}_a x = \operatorname{ind}_a y

注意:在取离散对数之后,取模变为 δma\delta_m a,而不是原来的 mm

求法

BSGS 算法:在 O(m)O(\sqrt m) 的时间内求 ax=b(modm)a^x=b\pmod m 的解。要求 (a,m)=1(a,m)=1

t=mt=\lceil\sqrt m\rceil。不妨设解 x=itjx=it-j。(0jt0\le j \le t

aitjb(modm)a^{it-j} \equiv b \pmod m,即 aitbaj(modm)a^{it}\equiv ba^j \pmod m

求出 i,ji,j 后就能得到答案。(互质的原因是我们推导用到了逆元)

参考代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<bits/stdc++.h>
using ll=long long;
using namespace std;
ll ksm(ll a,ll b,ll p){
ll r=1;
while(b){
if(b&1)r=r*a%p;
a=a*a%p;
b>>=1;
}
return r;
}
int main(){
ll p,a,b;
scanf("%lld%lld%lld",&p,&a,&b);
ll t=ceil(sqrt(p));
map<ll,int>vis;
for(ll i=0,now=b;i<=t;i++,now=now*a%p)vis[now]=i;
ll at = ksm(a,t,p);
for(ll i=1,now=at;i<=t;i++,now=now*at%p){
if(vis.count(now)){
printf("%lld\n",i*t-vis[now]);
return 0;
}
}
puts("no solution");
return 0;
}

习题

P6091 【模板】原根

P3846 [TJOI2007] 可爱的质数/【模板】BSGS

[ABC335G] Discrete Logarithm Problems 参考代码