欧拉函数(φ)phi是OI中很重要的一块知识点,经常出现在各种数论题目里,所以这里就讲一下phi的求法以及最简单的应用。
φ(n)的含义是在1~n中与n互质的数的个数。那么这里有一个十分明显的结论,就是如果x为质数,则φ(x)=x-1,因为1~x-1都与x互质,都不是x的因数。下面我将介绍更多的关于phi的结论。
结论1:若x为质数,φ(x)=x-1(如上文)
结论2:若p为质数,k>1,则φ(p^k)=p^k-p^(k-1)=(p^k)*(1-1/p)。这个结论也十分容易证明,因为如果这个数为p^k,则与它不互质的数只必须有因数p,而包含p的是1×p,2×p……(p^(k-1))×p共p^(k-1)个。
结论3:phi是积性函数,所以若x和y互质,则φ(x*y)=φ(x)*φ(y)
结论4:(由结论2扩展可知),对于任意大于1的数,将其分解质因数得x=∏pi^ki。所以φ(x)=x*∏(1-1/pi)。
我们利用结论3,就可以进行线性筛欧拉函数,我们在进行欧拉筛的时候顺便进行欧拉函数的筛选,我们先看最普通的欧拉筛代码。
pri[0]=pri[1]=1;pri[2]=0;
for(int i=2;i<=n;i++){
if(!pri[i]) b[++top]=i;
for(int j=1;j<=top;j++){
if(i*b[j]>n) break;
if(i%b[j]){pri[i*b[j]]=1;}
if(i%b[j]==0){pri[i*b[j]]=1;break;}
}
}
我们发现(i%b[j])的情况也就是i和b[j]互质的情况,所以这时直接phi[i*b[j]]=phi[i]*phi[b[j]]即可。
那么对于(i%b[j]==0)的情况呢?这时phi[i*b[j]]=phi[i]*b[j],这里证明就不展开了
pri[0]=1;pri[1]=1;pri[2]=0;phi[1]=1;
for(int i=2;i<=n;i++){
if(!pri[i]){
b[++top]=i;phi[i]=i-1;
}
for(int j=1;j<=top;j++){
if(i*b[j]>n) break;
pri[i*b[j]]=1;
if(i%b[j]) phi[i*b[j]]=phi[i]*phi[b[j]];
else{
phi[i*b[j]]=phi[i]*b[j];break;
}
}
}
这一段就是求phi的过程,可知我们就是在欧拉筛的过程中加上了求phi的语句。
有些时候不需要线性求phi,则我们直接用结论4即可。
#include<bits/stdc++.h>
#define MAXN 40006
using namespace std;
int read(){
char c;int x;while(c=getchar(),c<'0'||c>'9');x=c-'0';
while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';return x;
}
int n,m,b[MAXN],pri[MAXN],phi[MAXN],top;
int main()
{
n=read(),m=read();
pri[0]=1;pri[1]=1;pri[2]=0;phi[1]=1;
for(int i=2;i<=n;i++){
if(!pri[i]){
b[++top]=i;phi[i]=i-1;
}
for(int j=1;j<=top;j++){
if(i*b[j]>n) break;
pri[i*b[j]]=1;
if(i%b[j]) phi[i*b[j]]=phi[i]*phi[b[j]];
else{
phi[i*b[j]]=phi[i]*b[j];break;
}
}
}
for(int i=1;i<=m;i++){
int x=read();printf("%d\n",phi[x]);
}
return 0;
}
一道简单的求phi题,BZOJ2190
Description
作为体育委员,C君负责这次运动会仪仗队的训练。仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图)。
现在,C君希望你告诉他队伍整齐时能看到的学生人数。
Input
共一个数N。
Output
共一个数,即C君应看到的学生人数。
Sample Input
4
Sample Output
9
Hint
【数据规模和约定】 对于 100% 的数据,1 ≤ N ≤ 40000
这题很明显,我们先去掉最左边的一行和最下面的一行,将答案加2,然后剩下的点(其横纵坐标均-1),如果其x和y互质,则这个点时可以被看到的,因为很明显若x=bq,y=bp(b>1),则(q,p)会挡住(x,y)。所以我们直接累加phi值即可。
#include<bits/stdc++.h>
#define ll long long
#define MAXN 40006
using namespace std;
ll read(){
char c;ll x;while(c=getchar(),c<'0'||c>'9');x=c-'0';
while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';return x;
}
ll n,m,b[MAXN],pri[MAXN],phi[MAXN],top,ans;
int main()
{
n=read();
if(n==1){puts("0");return 0;}
pri[0]=1;pri[1]=1;pri[2]=0;phi[1]=1;
for(ll i=2;i<=n;i++){
if(!pri[i]){
b[++top]=i;phi[i]=i-1;
}
for(ll j=1;j<=top;j++){
if(i*b[j]>n) break;
pri[i*b[j]]=1;
if(i%b[j]) phi[i*b[j]]=phi[i]*phi[b[j]];
else{
phi[i*b[j]]=phi[i]*b[j];break;
}
}
}
ans=2;
for(ll i=1;i<=n-1;i++) ans+=phi[i]*2;
printf("%lld",ans-1);
return 0;
}