筛法求欧拉函数(适用于1~n求欧拉的情况)
① 先写出线性筛算法的模板。
② 考虑特殊情况:若该数是质数$p$的话,那么该数的欧拉函数就是$p - 1$。
③ 每个数的欧拉函数与质因子的次数无关。例如:$N=2^{100}\times3^{100}$,但是N的欧拉函数还是$N\times(1-\frac{1}{2})\times(1-\frac{1}{3})$
④ 若$i \bmod primes[j] == 0$,由于$primes[j]$是$i$的一个质因子,并且在计算$i$的欧拉函数的时候已经计算了$primes[j]$出现的情况$(1-\frac{1}{primes[j]})$,所以$\varphi(primes[j]\times i)=primes[j]\times\varphi(i)$。
⑤ 若$i \bmod primes[j] != 0$,$primes[j]$就一定是$primes[j] \times i$的最小质因子,而且$primes[j]$不包含在$i$的质因子当中。由于$\varphi(i)=i \times (1-\frac{1}{p_1}) \times (1-\frac{1}{p_2}) \times…\times (1-\frac{1}{p_k})$,所以$\varphi(primes[j]\times i)=primes[j]\times i\times (1-\frac{1}{p_1})\times(1-\frac{1}{p_2})\times…\times(1-\frac{1}{p_k})\times(1-\frac{1}{primes[j]})$。最终就可以得到$\varphi(primes[j] \times i)=primes[j]\times \varphi(i)\times (1-\frac{1}{primes[j]})=\varphi(i)\times (primes[j]-1)$。
⑥ 代码如下所示:
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1000010;
int primes[N], cnt; //primes数组存所有的质因子,cnt是下标
int phi[N]; //欧拉函数
bool st[N]; //表示每个数是否被筛掉了
LL get_eulers(int n)
{
phi[1] = 1;
for (int i = 2; i <= n; i ++) //线性筛
{
if (!st[i]) //当前没有被筛过就是质数
{
primes[cnt ++] = i;
phi[i] = i - 1;
}
for (int j = 0; primes[j] <= n / i; j ++)
{
st[primes[j] * i] = true;
if (i % primes[j] == 0)
{
phi[primes[j] * i] = phi[i] * primes[j];
break;
}
phi[primes[j] * i] = phi[i] * (primes[j] - 1);
}
}
LL res = 0;
for (int i = 1; i <= n; i ++)
res += phi[i];
return res;
}
int main()
{
int n;
cin >> n;
cout << get_eulers(n) << endl;
return 0;
}
看你的看懂了tql
棒
tql
非常感谢你,尤其是那个表达式都写出来,瞬间明白了
牛的
if (i % primes[j] == 0)
{
phi[primes[j] * i] = phi[i] * primes[j];
break;
}
phi[primes[j] * i] = phi[i] * (primes[j] - 1);
这里为什么不能直接if else,,为什么要break;
想不通T~T
可以再去看看线性筛,我们是用最小质因子求的素数结果
很清楚,感谢
很清楚,感谢~