强烈鸣谢wddwjlss
题目大意:给出一个奇素数,求出他的原根的个数,多组数据。
这里先介绍一些基本性质
阶
设
(a,m)=1
(
a
,
m
)
=
1
,满足
ar≡1(modm)
a
r
≡
1
(
mod
m
)
的最小正整数r叫做整数a模m的阶
那么给出一个定理:
设
(a,m)=1
(
a
,
m
)
=
1
,r为a摸m的阶,则对于每个正整数k,
ak≡1(modm)
a
k
≡
1
(
mod
m
)
当且仅当
r|k
r
|
k
,特别地,
r|ϕ(m)
r
|
ϕ
(
m
)
阶的一些性质
设
(a,m)=1
(
a
,
m
)
=
1
,r为a摸m的阶,当且仅当二条件成立:
ar≡1(modm)
a
r
≡
1
(
mod
m
)
对于
r
r
的每个素因子p有
原根
若整数a模m的阶为 ϕ(m) ϕ ( m ) ,则a是模m的原根
对于正整数m,模m具有原根当且仅当 m=2,4,pa,2pa m = 2 , 4 , p a , 2 p a 其中p是奇素数,且 a≥1 a ≥ 1
判断原根的方法
g是不是模m的原根:
bool check(int g,int m)
{
for (int i=2;i*i<m;i++)
{
if ((m-1)%i==0 && (qsm(g,i,m)==1 || qsm(g,(m-1)/i,m)==1)) return false
}
return true;
}
其中 m为素数 m 为 素 数 , m−1是指ϕ(m) m − 1 是 指 ϕ ( m )
运用的是上面的第二个推论
同时!!!!一个很重要的性质
如果 p p 有原根,则它恰有个不同的原根(无论 p p 是否为素数都适用)
那么对于上述的题目
我们要求的原根个数,其实就是求 ϕ(p−1) ϕ ( p − 1 )
直接线性筛
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 1e5+1e2;
int check[maxn],prime[maxn],phi[maxn];
int n,m;
int tot;
void init(int n)
{
check[1]=1;
phi[1]=1;
for (int i=2;i<=n;i++)
{
if (!check[i])
{
prime[++tot]=i;
phi[i]=i-1;
}
for (int j=1;j<=tot;j++)
{
if (i*prime[j]>n) break;
check[i*prime[j]]=1;
if (i%prime[j]==0)
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
else
{
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}
}
int main()
{
init(100000);
while (scanf("%d",&n)!=EOF)
{
printf("%d\n",phi[n-1]);
}
return 0;
}