设
任何非零整数
其中
证明
唯一性仍可简化到
由于
再次应用欧几里得引理可见
对于任何素数
考虑正整数
对于任意多个正整数的
定义
设正整数
求
若
素数列
存在无穷多个素数。
证明
则
给定正整数
我们试图制造一个筛子。
我们把整数
筛完之后,筛子里剩下的就是不超过
vector<int> get_primes(int n) {
vector<int> primes;
vector<bool> is_prime(n + 1, true);
for (int i = 2; i <= n; i++)
if (is_prime[i]) {
primes.push_back(i);
for (int j = 2 * i; j <= n; j += i)
is_prime[j] = false;
}
return primes;
}
时间复杂度:
给定正整数
对于实数
设
设
证明:根据定义,我们有
当
当
显然有
对于任意正整数
设
将
显然有
给定正整数
计算
我们需要计算的子问题形如
设
例如
设
其中
在
设
设
也就是说,对于
设
令
根据上一个命题,有
又
即
即
令
其中,
long long prime_count(long long n) {
const int k = (int) sqrt(n);
vector<long long> v(k + 1);
for (int i = 1; i <= k; i++)
v[i] = n / i;
for (int i = n / (k + 1); i >= 1; i--)
v.push_back(i);
// 对于 i = 1, 2, ..., k+1 有 n/i == v[i-1]。
// 对于 i = 1, 2, ..., k 还有,i 是唯一的满足 n/d == n/i 的正整数 d。我们称这些值为大值。
const int m = (int) v.size();
vector<long long> f(m);
for (int i = 1; i < m; i++)
f[i] = v[i] - 1;
auto [p, lpf] = get_primes(k);
const int s = (int) p.size();
for (int i = 0; i < s; i++) {
f[1] -= f[p[i]] - i;
if (i == s - 1) break;
const long long L = (long long) p[i] * p[i];
const int lim = k / p[i];
for (int j = p[i + 1]; j < m && v[j] >= L; j++) {
if (j < k && lpf[j + 1] < p[i + 1]) continue;
if (j <= lim) {
f[j] -= f[j * p[i]] - i;
} else { // v[j] / p[i] <= k
f[j] -= f[m - v[j] / p[i]] - i;
}
}
}
return f[1];
}
时间: