Primitive root

高大上的数论,先入门再说。

原根的定义可以到wiki上找,上面介绍得很清楚。

如果你是个热(bu)爱(dong)祖(ying)国(yu)的人,看这个blog就行了

1、51nod 1135

奇怪的oj,还是放链接吧

求奇素数n最小的原根。

从2~n-1枚举x,判断x是否满足x^j mod n != 1    j=2,3,4,...,phi(n)-1

暴力判断会T,需要跟快的算法。

wiki介绍了一个方法。

设phi(n)=p1^k1*p2^k2......pm^km

那么x是n的一个原根充要条件为

x^(phi(n)/pj) mod n != 1  j = 1,2,3...m

证明:

若存在j使得x^(phi(n)/pj) mod n = 1,不必说,x不是原根

如不存在j满足条件,假设t满足x^t mod n = 1

那么x^(phi(n)-t) mod n =1

由辗转相除算法可知x^gcd(phi(n),t) mod n = 1

令d = gcd(phi(n),t), 即x^d mod n = 1

因为d|phi(n),所以至少有一个j满足d|phi(n)/pj,不妨设其为i

所以x^(phi(n)/pj) mod n = 1,与假设矛盾,得证


回归原题,由于n为素数,所以phi(n)=n-1,分解n-1后对每个pj检查一下即可

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
int prime[100000];
bool check[100000];
int P,i,cnt,tot,p[1000];

void init(){
  for (int i=2;i<100000;i++){
  	if (!check[i]) prime[++tot]=i;
  	for (int j=1;j<=tot;j++){
  	  if (i*prime[j]>=100000) break;
  	  check[i*prime[j]]=true;
  	  if (i%prime[j]==0) break;
  	}
  }
}

int qck(int a,int b){
  int ret = 1;
  for (;b>0;b>>=1){
    if (b&1) ret=(long long)ret*a%P;
    a = (long long)a*a%P;
  }
  return ret;
}

bool Judge(int x){
  for (int i=1;i<=cnt;i++)
  if (qck(x,(P-1)/p[i])==1)
    return 0;
  return 1;
}

void Analyze(int x){
  cnt = 0;
  for (int i=1;i<tot;i++)
  if (x%prime[i]==0)
  	p[++cnt] = prime[i];
}

int main(){
  //freopen("1135.in","r",stdin);
  //freopen("1135.out","w",stdout);
  init();
  while (~scanf("%d",&P)){
  	Analyze(P-1); 
    for (i=2;i<P;i++)
	  if (Judge(i)) break;
	printf("%d\n",i);
  }
  return 0;
}

2、poj1284 primitive roots

求一个奇素数的原根数量。

wiki上给了一个定理:如果n有原根,那么n的原根数量为phi( phi(n) )

n有原根的充要条件是n可以写成以下形式中的一种:2,4,p^k,2*p^k   其中p为奇素数

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
int n,tot;
int prime[100000];
int phi[100000];
bool check[100000];

void init(){
  phi[1] = 1;
  for (int i=2;i<100000;i++){
  	if (check[i]==0){
  	  prime[++tot] = i;
  	  phi[i] = i-1;
  	}
  	for (int j=1;j<=tot;j++){
  	  if (i*prime[j]>=100000) 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(){
  freopen("poj1284.in","r",stdin);
  freopen("poj1284.out","w",stdout);
  init();
  while (~scanf("%d",&n))
    printf("%d\n",phi[n-1]);
  return 0;
}


你可能感兴趣的:(root,Primitive)