原根与阶
定义
设 a,m 两数互质,满足 ax≡1(mod m) 的最小的 x,称为 a 对 m 的阶,记为 ordm(a)。
当 ordm(a)=ϕ(m) 时称为 a 为 m 的一个原根。
性质
1.
a
x
≡
1
⇔
o
r
d
m
(
a
)
∣
x
a^x≡1⇔ord_m(a)∣x
ax≡1⇔ordm(a)∣x
2.
o
r
d
m
(
a
)
∣
ϕ
(
m
)
ord_m(a)∣ϕ(m)
ordm(a)∣ϕ(m)
3. n有原根⇔
n
∈
2
,
4
,
p
e
,
2
∗
p
e
n∈{2,4,p^e,2*p^e}
n∈2,4,pe,2∗pe(p为奇素数)
4. 一个数的最小原根的大小不超过
m
1
4
m^{\frac{1}{4}}
m41
5. 若g是m的一个原根,那么gd是m的原根的充分必要条件是gcd(d,Φ(m))=1,由此可推知一个数的原根个数为Φ(Φ(m))个
6.
o
r
d
m
(
a
d
)
=
o
r
d
m
(
a
)
o
r
d
m
(
a
)
,
d
ord_{m}(a^{d})=\frac{ ord_m(a) }{ ord_m(a),d }
ordm(ad)=ordm(a),dordm(a)(利用这个性质可以求出所有原根)
7.
a
0
,
a
1
,
…
,
a
o
r
d
m
(
a
)
−
1
a^0,a^1,…,a^{ord_m(a)−1}
a0,a1,…,aordm(a)−1 构成摸m的既约剩余系
8.
a
x
≡
a
y
a^x≡a^y
ax≡ay(mod m)
⇔
x
≡
y
(
m
o
d
o
r
d
m
(
a
)
)
⇔x≡y(mod ord_m(a))
⇔x≡y(modordm(a))
9. 设
ϕ
(
m
)
=
p
1
r
1
p
2
r
2
…
p
K
r
k
ϕ(m)=p_1^{r1}p_2^{r2}…p_K^{rk}
ϕ(m)=p1r1p2r2…pKrk,则g是m的原根⇔对与所有的pi,
g
ϕ
(
m
)
p
i
≠
1
g^{\frac{ϕ(m)}{p_i}}≠1
gpiϕ(m)=1(mod m)
求解
- 判断一个数是否有原根。(枚举质数)
- 求得最小原根。(依次枚举 2 ~ m 1 4 2~ m^{\frac14} 2~m41 判断)
- 求出所有原根。(枚举次数d)
代码
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4992
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
const int N=1000000;
bool f[1000000];
int phi(int x)
{
if (f[x]) return x-1;
int ans=x;
for (int i=2;i<=x;i++)
if (x%i==0)
{
while (x%i==0) x/=i;
ans=ans-ans/i;
}
return x>1?ans-ans/x:ans;
}
int gcd(int a,int b)
{
swap(a,b);
int c=a%b;
while (c) a=b,b=c,c=a%b;
return b;
}
int quick_mod(int x,int p,int mod)
{
long long s=1,a=x;
while (p)
{
if (p&1) s=(s*a)%mod;
a=a*a%mod,p>>=1;
}
return (int)s;
}
vector<int> V,G;
void cal(int x)
{
G.clear();
if (f[x]) return;
else for (int i=2;i*i<=x;i++)
if (x%i==0)
{
G.push_back(i);
if (i*i!=x) G.push_back(x/i);
}
}
bool exist(int n)
{
if (n%2==0) n/=2;
if (f[n]) return 1;
for (int i=3;i*i<=n;i+=2){
if (n%i==0){
while (n%i==0) n/=i;
return n==1;
}
}
return 0;
}
bool solve(int n)
{
if (n==4||n==2) return printf("%d\n",n-1),0;
if (!exist(n)) return printf("-1\n");
int p=phi(n),x=-1;
cal(p);
for (int i=2;i<n;i++)
if (quick_mod(i,p,n)==1)
{
bool flag=1;
for (int j=0;j<G.size()&&flag;j++)
if (quick_mod(i,G[j],n)==1) flag=0;
if (flag)
{
V.resize(1),V[0]=x=i;
break;
}
}
if (x==-1) return printf("-1\n"),0;
for (int i=2;i<p;i++)
if (gcd(i,p)==1) V.push_back(quick_mod(x,i,n));
sort(V.begin(),V.end());
vector<int>::iterator it=unique(V.begin(),V.end());
V.erase(it,V.end());
for (int i=0;i<V.size();i++)
{
if (i) printf(" ");
printf("%d",V[i]);
}
return printf("\n"),0;
}
int main()
{
memset(f,1,sizeof(f));
f[0]=f[1]=0;
for (int i=2;i<1000000;i++)
if (f[i])
for (int j=i<<1;j<1000000;j+=i) f[j]=0;
int n;
while (~scanf("%d",&n)) solve(n);
return 0;
}