poj2478题解-欧拉函数(Farey Sequence)

poj2478题解-欧拉函数

前言

先点关注,不迷路

大家好,我是于斯为盛
这一段刚好在学欧拉函数,说实话刚看到这道题的时候我还是有点懵的
通过这道题,我也意识到了define的重要性
哎,两个地方少打了零
废话不多说
原题传送门: 点这里.
讲得不好勿喷~

暴力方法

暴力方法我想很多人都能想明白
无非就是三层循环

	while 输入n
		for 循环分母
			for 循环分子

最多加个前缀和,打个表的优化

	for 循环分母
		for 循环分子//打表
	while 输入,从表中读取

但是…
O(n2),n=106
也就是最少1012
或许可以找个超算中心

所以暴力方法有什么用呢?

我认为,虽然不能过
但是日后调试也是有大用处的

欧拉函数优化

欧拉函数不知道大家知不知道
φ(m)表示m以内与m互素的数的个数

题目里要求分母在n以内且分子整除分母且小于分母的个数
可以转化为Σφ(i)

然后这里有一个求φ的方法
设:m=p1^e1 * p2^e2……(唯一分解定理,pi为素数)
则φ(m)=m*(1-1/p1)*(1-1/p2)……
证明的话点这里

但是这里注意到1/pi是个分数
我们不妨把上式通分
得到φ(m)=m*((p1-1)/p1 )*((p2-1)/p2 )……
由于pi|m
在除的时候不会出现小数

还有要注意一点,在循环pi的时候不是单纯的看是不是整除
而还要做一个素数筛法
我这里用的埃氏筛法

	while 输入n
		for i循环1~n,求φ(m),累和
			for m循环1~根号i(大于根号i的素数因子最多有一个,后面单独处理即可)
				for k循环m, k*m<=根号i(埃氏筛法找合数)
				//因为当k<m时,k*m已经被前面的素数筛掉了,所以从m*m开始
				//当k*m大于根号i时,后面的数反正单独处理,筛它也没用

但是这样也没有太大的优化效果

打表+欧拉函数优化

打表前文已经提过了
把求φ的过程提到前面

```c
	for i循环1~n,求φ(m),累和
		for m循环1~根号i(大于根号i的素数因子最多有一个,后面单独处理即可)
			for k循环m, k*m<=根号i(埃氏筛法找合数)
			//因为当k<m时,k*m已经被前面的素数筛掉了,所以从m*m开始
	while 输入n

这样,我们把复杂度提到了O(n* 根号n* 根号n)甚至还要小
等等!!!没完呢!!!
我先把代码粘一下
但是可能有人发现了
O(n* 根号n* 根号n)当n=106时复杂度还是差点

//code by 于斯为盛
#include <iostream>

using namespace std;

long long _fai[1000005];//φ,应该是phi~后文为了省事,变成了存前缀和的数组
//ps:十年OI一场空,不开long long见祖宗
bool _use[1005];//素数表,我懒的取名字了
int _n;

void GenFai<
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值