定义:1-n中与n互质的数的个数被称为欧拉函数。
求法:n*(1-1/pi),其中pi是n的所有质因数
性质1-6 见书P139 (这是一个积性函数)
积性函数定义:当a,b互质的时候,f(a*b)=f(a)*f(b)
例题:POJ 3090
这个题本质求得就是i=2-n中与i互质的数的个数的和,然后再进行一些操作。
写法1
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=1005;
int c,f[maxn];
void work(int num,int n)
{
int sum=0;
for(int i=2;i<=n;i++) f[i]=i;
for(int i=2;i<=n;i++)
{
if(f[i]==i)//i是质数
{
for(int j=i;j<=n;j+=i)
{
f[j]=f[j]/i*(i-1);
}
//这里同时也会把f[i]=i-1
}
sum+=f[i];
}
printf("%d %d %d\n",num,n,sum*2+3);
}
int main()
{
int n;
scanf("%d",&c);
for(int t=1;t<=c;t++)
{
scanf("%d",&n);
work(t,n);
}
return 0;
}
很好理解:用质因数去更新每个f[i]的值。
然而我们可以借鉴分解质因数的优化。
由于性质4,5:
若p整除n,p*p整除n: f(n)=f(n/p)*p
若p整除n,p*p不整除n: f(n)=f(n/p)*(p-1)
那么我们若是知道f(n/p)的值,我们就可以用最小的p以及f(n/p)来更新他。
emm就是这样。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=1005;
int v[maxn],prime[maxn],f[maxn];
void work(int num,int n)
{
memset(v,0,sizeof(v));//最小质因子
int m=0;//质数数量
int sum=0;
for(int i=2;i<=n;i++)
{
if(v[i]==0)
{
v[i]=i;prime[++m]=i;
f[i]=i-1;
}
for(int j=1;j<=m;j++)//但凡合数一定能被枚举到
{
if(prime[j]>v[i]||prime[j]>n/i) break;
//i有比prime[j]更小的因子或者超出n
v[i*prime[j]]=prime[j];
f[i*prime[j]]=f[i]*(i%prime[j]?prime[j]-1:prime[j]);
//性质4与性质5
}
sum+=f[i];
}
printf("%d %d %d\n",num,n,sum*2+3);
}
int main()
{
int n;int c;
scanf("%d",&c);
for(int t=1;t<=c;t++)
{
scanf("%d",&n);
work(t,n);
}
return 0;
}