欧拉函数

定义: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;
} 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值