欧拉函数
在数论,对正整数n,欧拉函数是小于n的正整数中与n互质的数的数目(φ(1)=1) 例如φ(8)=4,因为1,3,5,7均和8互质。
欧拉函数有如下基本定理:
一: 是积性函数,设m与n是互素的正整数,那么;
二: :当n为奇数时,有
三: 设p是素数,a是一个正整数,那么
证明:(
由于表示小于
与
互素数的正整数个数,所以用
减去与它不互素的数的个数就行了。
那么小于与
不互素数的个数就是p的倍数个数,有
个。所以定理得证。
四: 设为正整数n的素数幂分解,那么
五: 设n是一个正整数,那么
六: 设n 是一个大于2 的正整数,则 φ(n)是偶数
常用的两个定理:
费马小定理:
当p是质数时 a(p-1)≡1(mod p) : 简化幂运算
欧拉定理:
对于和m互素的x,有xφ(m)≡1(mod m)
直接求法: 适用于求单个 phi值时 此时时间复杂小, 且空间小;
int gphi(int n)
{
int temp=n;
for(int i=2;i<=n;i++)
{
if(n%i==0)
{
temp-=temp/i;
while(n%i==0)
n/=i;
}
}
if(n>1)
temp-=temp/n;
return temp;
}
模板 求 欧拉函数值;
void get_phi(int n)// p是素数
{
cont=0;
memset(vis,0,sizeof(vis));
for(int i=2; i<=n; i++)
{
if(!vis[i])
{
p[++cont]=i;
phi[i] = i-1;
}
for(int j=1; j<=cont && p[j]*i<=n; j++)
{
vis[p[j]*i]=1;
if(i%p[j]==0)
{
phi[i*p[j]] = p[j] * phi[i]; //欧拉函数性质
break;
}
else phi[i*p[j]] = (p[j]-1) * phi[i];
}
}
}
递推法求欧拉函数值:
复杂度 O (nln n)
void iinit()
{
for(int i=1;i<=N;i++) phi[i]=i;
for(int i=2;i<=N;i+=2)phi[i]>>=1;
for(int i=3;i<=N;i+=2){
if(phi[i]==i)
{
for(int j=i;j<=N;j+=i)
phi[j]=phi[j]-phi[j]/i;
}
}
}
看一下应用:
例题一: POJ 2407 http://poj.org/problem?id=2407
最简单的意思: 求 φ(n)
直接用第一个:其余的打表模板, 空间占有量太大 n的范围是10^9 次方
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long ll;
int gphi(int n)
{
int temp=n;
for(int i=2;i<=n;i++)
{
if(n%i==0)
{
temp-=temp/i;
while(n%i==0)
n/=i;
}
}
if(n>1)
temp-=temp/n;
return temp;
}
int main()
{
int n;
while(cin>>n&&n)
{
cout<<gphi(n)<<endl;
}
return 0;
}
例题2 : POJ 1284 http://poj.org/problem?id=1284
原根: 求 x^i mod p = [1,p-1] p原根的个数;
这里用到一个结论 如果p 是素数, 则有 φ(p-1)个原根;
直接和上面的代码一样, 输出 gphi(n-1)即可;'
例题3 : POJ 2478 http://poj.org/problem?id=2478
f2= 1,f3 =3 f4=5, f5 =9 f6=11;
而 前10项 φ值为 1 1 2 2 4 2 6 4 6 4 可以发现 f(n)= 从第二项开始 前φ(n)项的和
所以 递推打表
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long ll;
const int N=1000011;
ll phi[N+10];
void iinit()
{
for(int i=1;i<=N;i++) phi[i]=i;
for(int i=2;i<=N;i+=2)phi[i]>>=1;
for(int i=3;i<=N;i+=2){
if(phi[i]==i)
{
for(int j=i;j<=N;j+=i)
phi[j]=phi[j]-phi[j]/i;
}
}
for(int i=3;i<=N;i++)
phi[i]+=phi[i-1];
}
int main()
{
int n;
iinit();
while(cin>>n&&n)
{
cout<<phi[n]<<endl;
}
return 0;
}