欧拉函数
定义
在数论中 ,对正整数n,欧拉函数是小于或等于n的数中与n互质的数的数目,记做phi(n)。
如φ(8)=4,因为1,3,5,7均和8互质。
性质
- 若n=(p1a1) * (p2a2) * …… * (pkak) (为N的分解式),则φ(n)=n * (1-1/p1) * (1-1/p2) * …… * (1-1/pk) 如果n为某一个素数p,则φ(p )=p-1 如果n为任意两个数a和b的积,那么φ(a*b)=φ(a)*φ(b) 如果i mod p = 0, 那么phi(i * p)=p * phi(i)
- p^k的欧拉函数
对于给定的一个素数p,我们知道φ ( p) = p-1。
假设一个整数n是p的k次幂,也就是 n = pk,k∈N+
容易证明 φ(n) = pk - p(k-1)
证明: 已知小于pk的正整数个数为pk-1个,其中
和pk不互质的正整数有{p×1,p×2,…,p×(p(k-1)-1)}共计p(k-1)-1个
所以φ(n) = pk-1 - (p(k-1)-1) = pk - p(k-1)
积性函数
对于正整数n的一个函数 f(n),当中f(1)=1且当a,b互质,f(ab)=f(a)f(b),在数论上就称它为积性函数。 若某函数f(n)符合f(1)=1,且就算a,b不互质,f(ab)=f(a)f(b),则称它为完全积性函数。
欧拉函数,gcd(n,k)(当k固定时)都是积性函数
线性筛代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<stack>
#include<deque>
#include<iostream>
using namespace std;
typedef long long LL;
const int N = 100009;
int check[N];
int prime[N]; //存储素数
int phi[N]; //存储欧拉函数
int cnt;
void is_prime(int n)
{
int i,j;
cnt=0;
phi[1]=1;
for(i=2; i<=n; i++)
{
if(!check[i])//判断是不是素数
{
prime[cnt++]=i;//存储素数
phi[i]=i-1; //欧拉函数
}
for(j=0; j<cnt; j++)//遍历所有的素数
{
if(i*prime[j]>n)
break;
check[i*prime[j]]=1; //将出现过的所有的素数的i倍标记为合数
//说明i的因子中含有prime[j],即i唯一分解后,最小质 因子是prime[j]。
//因为prime[k](k > j) 都是大于prime[j]的,根据 线性筛的思想(保证每个合数只会被它的最小质因数筛去),所以prime[j]之后的素数都不能去筛prime[j]]*i, break.
if(i%prime[j]==0) //例:当i等于6时,i = 2^2 * 3,所以任何数与i相乘, 乘积的最小质因子肯定是要小于等于2的。
{
//(下面这一段注释是我之前写的,现在无法理解了.....)
/*因为 i%prime[j]==0 ,所以i 是 prime[j] 的倍数, i 就可以看成 prime[j]*k , 这样
就相当于筛去 prime[i]的k*prime[j+1] 倍,但是这个数不应当现在被处理,而是在 i==prime[j+1]*k时被筛掉 */
phi[i*prime[j]]=phi[i]*prime[j]; // 因为prime[j] 是质数,所 以prime[j] 不可再分解,因此 i*prime[j] 的分解形式为i的分解形式再乘以prime[j],
// 欧拉函数性质: 如果i mod p = 0, 那么phi(i * p)=p * phi(i)
break;
}
else
phi[i*prime[j]]=phi[i]*(prime[j]-1);
//当 i 不是 prime[j] 的倍数的时候,欧拉函数为完全积性函数,满足积性函数的特点
}
//欧拉函数性质: 设m和n 是互质的正整数,那么phi(mn) = phi(m) * phi(n)
}
}
int main()
{
int i;
is_prime(100);
for(i=0; i<cnt; i++)
{
printf("%d %d\n",prime[i],phi[prime[i]]);
}
return 0;
}
POJ 2407
#include<stdio.h>
#include<stdlib.h>
long long eular(long long n)
{
long long ret=n,i;
for(i=2; i*i<=n; i++)
{
if(n%i==0)
{
n/=i;
ret=ret/i*(i-1);
while(n%i==0)
{
n/=i;
}
}
}
if(n>1) ret=ret/n*(n-1);
return ret;
}
int main ()
{
long long n,s;
while(~scanf("%lld",&n))
{
if(n==0)
break;
s=eular(n);
printf("%lld\n",s);
}
return 0;
}