POJ1284 Primitive Roots-欧拉函数求原根个数

转自http://blog.sina.com.cn/s/blog_6a46cc3f0100tvsq.html

这一题主要是用到了两个定理:

1)所有的奇素数都是有原根的

2)一个数n有原根,那么他有phi(phi(n))个模n不同余的原根(n是否素数都可用)

3)一个素数有原根,则有phi(n-1)个原根

证明:假设奇素数n的原根为r,那么r,r^1,r^2...r^phi(n)是模n不同于的,

由于(r^i)^(phi(n))=(r^phi(n))^i=1(mod n)1<=i<=phi(n),所以对于r^2,r^3..r^phi(n)来说ord(sub n) a|phi(n),phi(n)r^in的阶的倍数

又因为只有当(i,phi(n))=1时,r^i才是模n的原根,所以一共有phi(phi(n))个原根。

详见<<初等数论及其应用>>第九章

 

 

m是正整数,a是整数,若am的阶等于φ(m),则称a为模m的一个原根。(其中φ(m)表示m的欧拉函数)

假设一个数g对于P来说是原根,那么g^i mod P的结果两两不同,且有 1<g<P, 0<i<P,那么g可以称为是P的一个原根

归根到底就是g^(P-1) = 1 (mod P)当且当指数为P-1的时候成立.(这里P是素数).

简单来说,g^i mod p  g^j mod p p为素数)

其中iji, j介於1(p-1)之间

gp的原根。

算法】定理1:如果p有原根,则它恰有φ(φ(p))个不同的原根(无论p是否为素数都适用)

{x^i%p | 1 <= i <= p - 1} = {1,2,...,p-1} 等价于 {x^i%(p-1) | 1 <= i <= p - 1} = {0,1,2,...,p-2},

即为(p-1)的完全剩余系若x,x2...x(p-1)(p-1)的完全剩余系,根据定理,可以推出若 gcd(x, p-1) = 1,

(1,x,...,x(p-2))也是(p-1)的完全剩余系 因为若x^i != x^j (mod p-1),那么x*x^i != x*x^j (mod p-1),

与条件m矛盾,所以 x^i = x^j (mod p-1), 由此可以确定答案为Euler(p-1)

#include<cstdio>

#include<cstdlib>

#include<cstring>

#include<cmath>

#include<algorithm>

using namespace std;

const int maxn=100000;

int pr[maxn], phi[maxn];

void makephi()

{

    memset(phi, 0, sizeof(phi));

    pr[0]=0;

    for(int i=2; i<=maxn; i++)

    {

        if(!phi[i])pr[++pr[0]]=i, phi[i]=i-1;//素数,pr[0]记录个数

        for(int j=1; j<=pr[0]&&(i*pr[j]<=maxn); j++)

        {

            if(i%pr[j])phi[pr[j]*i]=phi[pr[j]]*phi[i];

            else

            {

                phi[pr[j]*i]=phi[i]*pr[j];

                break;

            }

        }

    }

    phi[1]=1;

}

int main()

{

    makephi();

    int n;

    while(~scanf("%d", &n))

    {

        printf("%d\n", phi[n-1]);//或是phi[phi[n]]

    }

    return 0;

}

#include <cstdio>
#include <cmath>
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
//欧拉函数 
int Euler(int n){
	int euler = n;
	for(int i = 2;i*i <= n;i++){	//筛n的质因数 
		if(n % i == 0){		//找到质因数 
			euler = euler / i * (i-1);
			n /= i;
		}
		while(n % i == 0)
			n /= i;
	}
	if(n != 1)
		euler = euler / n * (n-1);
	return euler;
	
}

int main(){
	int n;
	while(scanf("%d",&n) != EOF){
		int ret = Euler(Euler(n));
		printf("%d\n",ret);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/lmhlmh_/article/details/80466337
今日推荐