互质
∀ \forall ∀a,b ∈ N,若 gcd(a,b)==1,则称 a,b 互质。
欧拉函数
定义
1 ~ N 中与 N 互质的数的个数被称作欧拉函数,记作 ϕ(N)。
若在算术直奔定理中,N = p1c1 p2c2 …… pmcn,则:
ϕ(N) = N *
p
1
−
1
p
1
{{p1-1} \over {p1}}
p1p1−1 *
p
2
−
1
p
2
{{p2-1} \over {p2}}
p2p2−1 ……
p
m
−
1
p
m
{{pm-1} \over {pm}}
pmpm−1 = N *
∏
\prod
∏(1-
1
p
{{1} \over {p}}
p1) (质数 p|N)
性质
- pk型欧拉函数:
若n是质数p(即n=p), φ(n) = φ( p ) = p - p(k-1) = p - 1。
若n是质数p的k次幂(即n = pk),φ(n) = pk - p(k-1)=(p-1)p(k-1)。 - mn型欧拉函数
设n为正整数,以φ(n)表示不超过n且与n互素的正整数的个数,称为n的欧拉函数值。
若m,n互质,φ(mn)=(m-1)(n-1)=φ(m)φ(n)。
若m|n,φ(m,n) = mφ(n). - 特殊性质:
若n为奇数时,φ(2n)=φ(n)。
对于任何两个互质的正整数a,n(n>2)有:
aφ(n) ≡ 1 (mod n),此公式即 欧拉定理。
当n = p 且 a与素数p互质(即:gcd(a,p)=1)则上式有:
a(p-1) ≡ 1 (mod n),此公式即 费马小定理。
§模板1:
int pri[maxn],tot;
bool v[maxn];
void primes()
{
tot = 0;
memset(v,true,sizeof(v));
for(int i=2;i<maxn;i++){
if(v[i])
pri[++tot] = i;
for(int j=1;j<=tot&&pri[j]*i<maxn;j++){
v[i*pri[j]] = false;
if(i%pri[j]==0) break;
}
}
}
int phi(int n)
{
int ans = n;
for(int i=1;pri[i]*pri[i]<=n;i++){
if(n%pri[i]==0){
ans = ans/pri[i]*(pri[i]-1);
while(n%pri[i]==0)
n /= pri[i];
}
}
if(n>1) ans = ans/n*(n-1);
return ans;
}
§模板2:
int pri[maxn],tot;
bool v[maxn];
void primes()
{
tot = 0;
memset(v,true,sizeof(v));
for(int i=2;i<maxn;i++){
if(v[i])
pri[++tot] = i;
for(int j=1;j<=tot&&pri[j]*i<maxn;j++){
v[i*pri[j]] = false;
if(i%pri[j]==0) break;
}
}
}
int phi(int n)
{
int ans = 1;
for(int i=1;pri[i]*pri[i]<=n;i++){
if(n%pri[i]==0){
ans *= (pri[i]-1);
n /= pri[i];
while(n%pri[i]==0){
ans *= pri[i];
n /= pri[i];
}
}
}
if(n>1) ans *= (n-1);
return ans;
}
例题:POJ 1284 Primitive Rootshttp://poj.org/problem?id=1284
Description
We say that integer x, 0 < x < p, is a primitive root modulo odd prime p if and only if the set { (xi mod p) | 1 <= i <= p-1 } is equal to { 1, …, p-1 }. For example, the consecutive powers of 3 modulo 7 are 3, 2, 6, 4, 5, 1, and thus 3 is a primitive root modulo 7.
Write a program which given any odd prime 3 <= p < 65536 outputs the number of primitive roots modulo p.
Input
Each line of the input contains an odd prime numbers p. Input is terminated by the end-of-file seperator.
Output
For each p, print a single number that gives the number of primitive roots in a single line.
Sample Input
23
31
79
Sample Output
10
8
24
题意
求模素数p的原根个数
结论:如果p是素数,则模p必有原根,其个数为ϕ(p−1)
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
#include<ctime>
#define ll long long
#define ld long double
#define ull unsigned long long
using namespace std;
const int maxn = 300;
const ll lnf = 0x3f3f3f3f3f3f3f;
int pri[maxn],tot;
bool v[maxn];
void primes()
{
tot = 0;
memset(v,true,sizeof(v));
for(int i=2;i<maxn;i++){
if(v[i])
pri[++tot] = i;
for(int j=1;j<=tot&&pri[j]*i<maxn;j++){
v[i*pri[j]] = false;
if(i%pri[j]==0) break;
}
}
}
int phi(int n)
{
int ans = 1;
for(int i=1;pri[i]*pri[i]<=n;i++){
if(n%pri[i]==0){
ans *= (pri[i]-1);
n /= pri[i];
while(n%pri[i]==0){
ans *= pri[i];
n /= pri[i];
}
}
}
if(n>1)ans *= (n-1);
return ans;
}
int main(void)
{
int n;
primes();
while(scanf("%d",&n)!=EOF){
printf("%d\n",phi(n-1));
}
return 0;
}