目录:
1.欧拉函数的定义
2.欧拉函数的通式
3.欧拉函数的性质
4.欧拉函数的单个求法
5.欧拉函数的打表求法
6.例题
欧拉函数,记作 φ ( n ) \varphi(n) φ(n),是闭区间 [ 1 , n ] [1,n] [1,n]中与n互质的数的个数,例如, φ ( 12 ) = 4 \varphi(12)=4 φ(12)=4,因为1,5,7,11与12互质
其中, p i p_i pi表示x用唯一分解定理分解后的所有质因数
其实很好理解,因为如果两个数互质,说明它们没有共同的质因数, [ 1 , n ] [1,n] [1,n]内共有n个数, ( 1 − 1 p k ) (1-{1\over p_k}) (1−pk1)表示[1,n]内没有 p k p_k pk这个质因数的数的比例,例如12,它的质因数是2,3,则 ( 1 − 1 2 ) (1-{1\over 2}) (1−21)表示有一半的数都是没有2这个质因数的, ( 1 − 1 3 ) (1-{1\over 3}) (1−31)表示有三分之二的数都是没有3这个质因数的,这样不断筛选下来最后剩下的个数就是与n互质的个数了.(也可以用容斥原理进行证明)
以下性质通过上述对通式的解释都很好证明 ?
利用通式的含义,筛出质因子并不断作乘法
int phi(int n)
{
int res=n;
for (int i=2;i*i<=n;i++)
{
if (n%i==0)
{
res=res/i*(i-1);//先进行除法防止中间数据的溢出
while(n%i==0)n/=i;
}
}
if (n>1)res=res/n*(n-1);
return res;
}
1.如果用求n次的单个欧拉函数的话时间复杂度是 O ( n n ) O(n\sqrt{n}) O(nn),不是很优的算法
2.下面这个算法的时间复杂度 O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))也蛮好理解的,当一个数的phi[i]=i时,说明其在之前的循环过程中尚未发现它的质因子,就从它开始把它的倍数都进行乘法处理
3 还有一种线性筛法,时间复杂度是 O ( n ) O(n) O(n)的
const int maxn=3e6+7;
int phi[maxn];
void phi_init()
{
phi[1]=1;
repp(i,2,maxn)phi[i]=i;
repp(i,2,maxn)
{
if (phi[i]==i)
{
for (int j=i;j<maxn;j+=i)
{
phi[j]=phi[j]/i*(i-1);
}
}
}
}
当 p 是 质 数 { 1. φ ( i p ) = φ ( i ) ∗ p , i % p = 0 2. φ ( i p ) = φ ( i ) φ ( p ) , i , p 互 质 当p是质数 \begin{cases} 1.\varphi(ip)=\varphi(i)*p,i\%p=0\\ 2.\varphi(ip)=\varphi(i)\varphi(p),i,p互质\\ \end{cases} 当p是质数{ 1.φ(ip)=φ(i)∗p,i%p=02.φ(ip)=φ(i)φ(p),i,p互质
第一条证明:
设 i p = p 1 k 1 p 2 k 2 p 3 k 3 … … p n k n ip=p_1^{k_1}p_2^{k_2}p_3^{k_3}……p_n^{k_n} ip=p1k1p2k2p3k3……pnkn,由于 i % p = = 0 i\%p==0 i%p==0,所有p的质因子都属于 p i ( 1 < = i < = n ) 集 合 内 p_i(1<=i<=n)集合内 pi(1<=i<=n)集合内,根据欧拉函数的通式可得: φ ( i p ) = i p ( 1 − 1 p 1 ) ( 1 − 1 p 2 ) ( 1 − 1 p 3 ) … … ( 1 − 1 p n ) \varphi(ip)=ip(1-{1\over p_1})(1-{1\over p_2})(1-{1\over p_3})……(1-{1\over p_n}) φ(ip)=ip(1−p11)(1−p21)(1−p31)……(1−pn1),可得 i ( 1 − 1 p 1 ) ( 1 − 1 p 2 ) ( 1 − 1 p 3 ) … … ( 1 − 1 p n ) = φ ( i ) i(1-{1\over p_1})(1-{1\over p_2})(1-{1\over p_3})……(1-{1\over p_n})=\varphi(i) i(1−p11)(1−p21)(1−p31)……(1−pn1)=φ(i),证毕
第二条证明:见博客?
int phi[maxn];
bool prime[maxn];//prime[i]=true表示i是质数
int primenum[maxn];//质数集合
int m=0;
void phi_init()
{
phi[1]=1;
memset(prime,true,sizeof prime);
prime[0]=prime[1]=false;
repp(i,2,maxn)
{
if (prime[i])
{
primenum[m++]=i;
phi[i]=i-1;
}
for (int j=0;j<m&&primenum[j]*i<maxn;j++)
{
prime[i*primenum[j]]=false;
if (i%primenum[j]==0)
{
phi[i*primenum[j]]=phi[i]*primenum[j];//第一条
break;//这里的break参考质数的线性筛解释
}
phi[i*primenum[j]]=phi[i]*phi[primenum[j]];//第二条
}
}
}
放一下质数线性筛做个对比
bool prime[maxn];
int m=1;
int primenum[maxn];
void prime_init()
{
memset(prime,true,sizeof prime);
prime[0]=prime[1]=false;
rep(i,2,maxn)
{
if (prime[i])primenum[m++]=i;
for (int j=1;j<m&&i*primenum[j]<=maxn;j++)
{
prime[i*primenum[j]]=false;
if (i%primenum[j]==0)break;
}
}
}
1.LightOJ - 1370
题意:给出n个数 x i x_i xi,求 ∑ i = 1 n a i \sum_{i=1}^na_i ∑i=1nai, a i a_i ai满足 φ ( a i ) > = x i \varphi(a_i)>=x_i φ(ai)>=xi
做法:预处理欧拉函数打表
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define pb push_back
#define rep(x,a,b) for (int x=a;x<=b;x++)
#define repp(x,a,b) for (int x=a;x
#define W(x) printf("%d\n",x)
#define WW(x) printf("%lld\n",x)
#define pi 3.14159265358979323846
#define mem(a,x) memset(a,x,sizeof a)
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
using namespace std;
const int maxn=1e6+7;
const int INF=1e9;
const ll INFF=1e18;
int prime[maxn];
int primenum[maxn];
int phi[maxn];
void phi_init()
{
int m=0;
rep(i,1,maxn)prime[i]=1;
prime[0]=prime[1]=0;
phi[1]=1;
repp(i,2,maxn)
{
if (prime[i])
{
primenum[m]=i;
m++;
phi[i]=i-1;
}
for (int j=0;j<m&&i*primenum[j]<maxn;j++)
{
prime[i*primenum[j]]=0;
if (i%primenum[j]==0)
{
phi[i*primenum[j]]=phi[i]*primenum[j];
break;
}
phi[i*primenum[j]]=phi[i]*(primenum[j]-1);
}
}
}
int main()
{
phi_init();
int t,n,a;
scanf("%d",&t);
rep(K,1,t)
{
scanf("%d",&n);
ll sum=0;
rep(i,1,n)
{
scanf("%d",&a);
for (int j=a+1;j<maxn;j++)
{
if (phi[j]>=a)
{
sum+=j;
break;
}
}
}
printf("Case %d: %lld Xukha\n",K,sum);
}
return 0;
}