poj1248 (线性筛欧拉函数)(原根)

强烈鸣谢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是奇素数,且\(a\ge 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\n",phi[n-1]);
  }
  return 0;
}

posted @ 2018-12-22 13:39  y_immortal  阅读(192)  评论(0编辑  收藏  举报