题目描述
给定一个正整数n,求1~n中每个数的欧拉函数之和。
数据范围:1≤n≤106
1~N中与N互质的数的个数被称为欧拉函数,记为ϕ(N)。
若在算数基本定理中,N=p_1^{\alpha_1}p_2^{\alpha_2}···p_k^{\alpha_k},则:
ϕ(N) = N∗\frac{p_1-1}{p_1}∗\frac{p_2-1}{p_2}∗…*\frac{p_k-1}{p_k}
线性筛法同时求欧拉函数
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1000010;
int primes[N], cnt;
int phi[N];
bool st[N];
void 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);
}
}
}
int main()
{
int n;
cin >> n;
get_eulers(n);
LL res = 0;
for (int i = 1; i <= n; i++) res += phi[i];
printf("%lld\n", res);
return 0;
}
代码解释:
- 质数i的欧拉函数即为
phi[i] = i - 1
:1 ~ i-1均与i互质,共i-1个。 phi[primes[j] * i]
分为两种情况:
①i % primes[j] == 0
时:primes[j]
是i
的最小质因子,也是primes[j] * i
的最小质因子,因此1 - 1 / primes[j]
这一项在phi[i]
中计算过了,只需将基数N修正为primes[j]
倍,最终结果为phi[i] * primes[j]
。
②i % primes[j] != 0
:primes[j]
不是i
的质因子,只是primes[j] * i
的最小质因子,因此不仅需要将基数N修正为primes[j]
倍,还需要补上1 - 1 / primes[j]
这一项,因此最终结果phi[i] * (primes[j] - 1)
。
# orz
orz
orz
orz
orz
orz
or2
# or2
orz
#~orz~
# ~orz~
orz考虑尝试 快速幂+ml素性测试+fd+tho断环得到所有的因子,再直接套欧拉公式即可
快速幂+ml素性测试
i64 gcd(i64 a, i64 b) { return b ? gcd(a, a % b) : a; } i64 mul(i64 a, i64 b, i64 m) { return static_cast<__int128>(a) * b % m; } i64 power(i64 a, i64 b, i64 m) { i64 res = 1 % m; for (; b; b >>= 1, a = mul(a, a, m)) if (b & 1) res = mul(res, a, m); return res; } bool isprime(i64 n) { if (n < 2) return false; static constexpr int A[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23 }; int s = __builtin_ctzll(n - 1); i64 d = (n - 1) >> s; for (auto a : A) { if (a == n) return true; i64 x = power(a, d, n); if (x == 1 || x == n - 1) continue; bool ok = false; for (int i = 0; i < s - 1; ++i) { x = mul(x, x, n); if (x == n - 1) { ok = true; break; } } if (!ok) return false; } return true; }
fd+tho断环
std::vector<i64> factorize(i64 n) { std::vector<i64> p; std::function<void(i64)> f = [&](i64 n) { if (n <= 200000000) { for (int i = 2; i * i <= n; ++i) for (; n % i == 0; n /= i) p.push_back(i); if (n > 1) p.push_back(n); return; } if (isprime(n)) { p.push_back(n); return; } auto g = [&](i64 x) { return (mul(x, x, n) + 1) % n; }; i64 x0 = 2; while (true) { i64 x = x0; i64 y = x0; i64 d = 1; i64 power = 1, lam = 0; i64 v = 1; while (d == 1) { y = g(y); ++lam; v = mul(v, std::abs(x - y), n); if (lam % 127 == 0) { d = gcd(v, n); v = 1; } if (power == lam) { x = y; power *= 2; lam = 0; d = gcd(v, n); v = 1; } } if (d != n) { f(d); f(n / d); return; } ++x0; } }; f(n); std::sort(p.begin(), p.end()); return p; }
欧拉公式直接法
i64 phi(int x){ auto t = factorize(x); t.erase(std::unique(t.begin(),t.end()),t.end()); for(auto&pi:t){ x = (x/pi)*(pi-1); } return x; }
这题解,看着舒服
这里解释一下为什么i不能被p[j]整除的情况下,i与p[j]互质。
因为p[j]是质数,其约数只有1和自身,i不能整除p[j],所以对于i和p[j]来说的最大公约数只有1,所以互质。
# ORZZZZZZZZZZ
orz
%%%%%
orz
orz
orz
tql orz
zro 番茄 orz
为什么没有初始化cnt呢?
感谢大佬,理解啦
写的太清楚了,比我自己总结的清楚太多了,直接抄了
南京邮电to东南 厉害的
or2
orz
泰裤辣orz
orz