原根的定义
首先引入数论中阶的定义
- 设 a ∈ Z , m ∈ N + a\in Z, m\in N^+ a∈Z,m∈N+,若 g c d ( a , m ) = 1 gcd(a,m)=1 gcd(a,m)=1,则称使得 a n ≡ 1 ( m o d m ) a^n\equiv 1(\mod m) an≡1(modm)成立的最小正整数 n n n为 a a a对膜 m m m的阶
接下来是原根的定义
- 设 a ∈ Z , m ∈ N + a\in Z, m\in N^+ a∈Z,m∈N+,若 g c d ( a , m ) = 1 gcd(a,m)=1 gcd(a,m)=1,且 a a a膜 m m m的阶为 φ ( m ) \varphi(m) φ(m),则 a a a为膜 m m m的原根
原根的求解
定理1:若 m ∉ { 2 , 4 } ⋃ { p α , 2 p α } m\notin \{2,4\}\bigcup\{p^\alpha,2p^\alpha\} m∈/{2,4}⋃{pα,2pα}(其中p为奇素数,α为整数),则膜m不存在原根
由该定理,我们可以先求素数表,然后预处理出每个数是否有原根
定理2:膜m的原根数量级别为 O ( m 0.25 ) O(m^{0.25}) O(m0.25)
定理3:若膜m存在原根,则其有 φ ( φ ( m ) ) \varphi(\varphi(m)) φ(φ(m))个原根
假设我们已求得膜
m
m
m的最小原根
g
g
g,那么膜
m
m
m的所有原根就是
{
g
k
∣
g
c
d
(
k
,
φ
(
m
)
=
1
)
}
\{g^k \ |\ gcd(k,\varphi(m)=1)\}
{gk ∣ gcd(k,φ(m)=1)}
所以我们可以直接从小到大枚举每个数判断其是否为膜m的原根
先得到膜m的最小原根g,再求g的幂次方以求得所有原根
为判断g是否为膜m的原根,在引入一个定理
定理4:设 a ∈ Z , m ∈ N + a\in Z, m\in N^+ a∈Z,m∈N+,若 g c d ( a , m ) = 1 gcd(a,m)=1 gcd(a,m)=1且 a k ≡ 1 ( m o d m ) a^k\equiv 1(\mod m) ak≡1(modm),则 k ∣ φ ( m ) k|\varphi(m) k∣φ(m)
易知若
g
g
g是膜
m
m
m的原根,则对所有
k
<
φ
(
m
)
k<\varphi(m)
k<φ(m)均有
g
k
m
o
d
m
≠
1
g^k \mod m \not= 1
gkmodm=1
结合定理4,我们只需要检查
φ
(
m
)
\varphi(m)
φ(m)的真因数d,若存在
g
d
≡
1
(
m
o
d
m
)
g^d\equiv 1(\mod m)
gd≡1(modm)则g不是原根
进一步的,我们只需要对 φ ( m ) \varphi(m) φ(m)质因数分解,检查所有 d = φ ( m ) p i d=\frac{\varphi(m)}{p_i} d=piφ(m)即可
const int maxn=1000010;
lt prim[maxn],phi[maxn],vis[maxn],cnt;
int has[maxn];
lt fac[maxn],facN;
lt rt[maxn],rtN;
lt gcd(lt a,lt b){ return b==0?a:gcd(b,a%b);}
lt qpow(lt a,lt k,lt mod)
{
lt res=1;
while(k){
if(k&1) res=(res*a)%mod;
a=(a*a)%mod; k>>=1;
}
return res;
}
void qPhi(lt n)
{
phi[1]=1;
for(lt i=2;i<=n;++i)
{
if(!vis[i]){ prim[++cnt]=i; phi[i]=i-1;}
for(int j=1;j<=cnt;++j)
{
if(i*prim[j]>n) break;
vis[i*prim[j]]=1;
if(i%prim[j]==0){ phi[i*prim[j]]=phi[i]*prim[j]; break;}
else phi[i*prim[j]]=phi[i]*phi[prim[j]];
}
}
}
void preWork(int lim)
{
has[2]=has[4]=1;
for(int i=2;i<=cnt;++i)
{
for(lt j=prim[i]; j<=lim; j*=prim[i]) has[j]=1; // p^α
for(lt j=prim[i]*2; j<=lim; j*=prim[i]) has[j]=1; // 2p^α
}
}
void div(int x)
{
facN=0;
for(int i=2;i*i<=x;++i)
{
if(x%i==0)
{
while(x%i==0) x/=i;
fac[++facN]=i;
}
}
if(x>1) fac[++facN]=x;
}
bool check(int g,int n)
{
if(qpow(g,phi[n],n)!=1) return false; // g^φ(n) ≡ 1 (mod n)
for(int i=1;i<=facN;++i){
if(qpow(g,phi[n]/fac[i],n)==1) return false;
}
return true;
}
int minRt(int n)
{
div(phi[n]); // 对φ(n)质因数分解并将质因子存在fac[]里
for(int i=1;i<=n;++i)
if(check(i,n)) return i;
return 0;
}
void allRt(int g,int n)
{
rtN=0;
lt t=1;
for(int i=1;i<=phi[n];++i)
{
t=t*g%n;
if(gcd(i,phi[n])==1) rt[++rtN]=t;
}
}
int main()
{
qPhi(maxn-10); // 质数表和phi
preWork(maxn-10); // 预处理每个数是否有原根
int T=read();
while(T--)
{
int n=read(),d=read();
if(!has[n])
{
printf("0\n\n");
continue;
}
lt g=minRt(n); // 求最小原根
allRt(g,n); // 求所有原根
printf("%d\n",rtN);
sort(rt+1,rt+1+rtN);
for(int i=d;i<=rtN;i+=d)
printf("%d ",rt[i]);
printf("\n");
}
return 0;
}
原根的应用
NTT
对于特定的膜数(一般是
P
=
r
2
k
+
1
P=r2^k+1
P=r2k+1),例如P=998244353
可以证明膜P的原根g满足
g
P
−
1
n
g^{\frac{P-1}{n}}
gnP−1与n次单位根
w
n
=
e
2
π
i
n
w_n=e^{\frac{2\pi i}{n}}
wn=en2πi有相同性质
因此可以将FFT中的n次单位根用原根替代,得到可以在膜意义下求值、插值的NTT
快速数论变换NTT
指标函数/离散对数
首先引入简化剩余系的定义
在与模m互素的全体剩余类中,从每个类各任取一个数组成的集合,称为模m的一个简化剩余系
易知模m的既约剩余系中的元素的个数为 φ ( m ) \varphi(m) φ(m)
而原根有如下定理
记 g g g对膜 m m m的阶为 δ \delta δ,则 g 0 , g 1 , . . . , g δ − 1 g^0,g^1,...,g^{\delta-1} g0,g1,...,gδ−1在膜m意义下互不相同
由该定理可得推论
若g为模m的原根,则 { g 0 , g 1 , g 2 , … … g φ ( m ) − 1 } \{g^0,g^1,g^2,……g^{φ(m)-1}\} {g0,g1,g2,……gφ(m)−1}组成模m的一个简化剩余系
定义指标函数
I
(
x
)
I(x)
I(x)满足
g
I
(
x
)
≡
x
(
m
o
d
m
)
g^{I(x)}\equiv x \pmod m
gI(x)≡x(modm)
那么有
I
(
g
x
m
o
d
m
)
=
x
I(g^x \mod m)=x
I(gxmodm)=x
该函数也称为离散对数,他和对数函数有很多相同性质
I
(
x
y
)
=
I
(
x
)
+
I
(
y
)
I(xy)=I(x)+I(y)
I(xy)=I(x)+I(y)
I
(
x
a
)
=
a
I
(
x
)
I(x^a)=aI(x)
I(xa)=aI(x)
由此可以解决一些需要在膜意义下进行对数运算的问题
例如求解同余方程
x
A
≡
B
(
m
o
d
C
)
x^A\equiv B(\mod C)
xA≡B(modC),其中C为素数(假设离散对数已知,实际中可用BSGS求解)
首先求得
B
B
B的离散对数
I
(
B
)
I(B)
I(B),由定义知其满足
g
I
(
B
)
≡
B
(
m
o
d
C
)
g^{I(B)}\equiv B(\mod C)
gI(B)≡B(modC)
又由原根定义有
g
φ
(
C
)
=
g
C
−
1
≡
1
(
m
o
d
C
)
g^{\varphi(C)}=g^{C-1}\equiv 1(\mod C)
gφ(C)=gC−1≡1(modC)
因此有
g
I
(
B
)
+
(
C
−
1
)
y
≡
B
(
m
o
d
C
)
g^{I(B)+(C-1)y}\equiv B(\mod C)
gI(B)+(C−1)y≡B(modC)
将该式带入原方程得
x
A
≡
g
I
(
B
)
+
(
C
−
1
)
y
(
m
o
d
C
)
x^A\equiv g^{I(B)+(C-1)y} (\mod C)
xA≡gI(B)+(C−1)y(modC)
两边同时取以g为底膜C意义下的离散对数得
A
I
(
x
)
≡
I
(
B
)
+
(
C
−
1
)
y
(
m
o
d
φ
(
C
)
)
A I(x)\equiv I(B)+(C-1)y (\mod \varphi(C))
AI(x)≡I(B)+(C−1)y(modφ(C))
当y取不同值时,可求出不同的
I
(
x
)
I(x)
I(x),计算
x
=
g
I
(
x
)
m
o
d
C
x=g^{I(x)}\mod C
x=gI(x)modC即可求得x
易知x共有
g
c
d
(
A
,
C
−
1
)
gcd(A,C-1)
gcd(A,C−1)个不同解