强烈鸣谢wddwjlss
题目大意:给出一个奇素数,求出他的原根的个数,多组数据。
这里先介绍一些基本性质
阶
设((a,m)=1),满足(a^r equiv 1 pmod m)的最小正整数r叫做整数a模m的阶
那么给出一个定理:
设((a,m)=1),r为a摸m的阶,则对于每个正整数k,(a^k equiv 1 pmod m) 当且仅当(r|k),特别地,(r|phi(m))
阶的一些性质
设((a,m)=1),r为a摸m的阶,当且仅当二条件成立:
(a^r equiv 1 pmod m)
对于(r) 的每个素因子p有(a^{r/p} 与1不同余 pmod m)
原根
若整数a模m的阶为(phi(m)),则a是模m的原根
对于正整数m,模m具有原根当且仅当(m=2,4,p^a,2p^a)其中p是奇素数,且(age 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-1是指phi(m))
运用的是上面的第二个推论
同时!!!!一个很重要的性质
如果(p)有原根,则它恰有(ϕ(ϕ(p)))个不同的原根(无论(p)是否为素数都适用)
那么对于上述的题目
我们要求(p)的原根个数,其实就是求(phi (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
",phi[n-1]);
}
return 0;
}