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<