Min_25 筛
Min_25 提出了 “Min_25 筛” 。之后,Min_25 还进行了改进,想了解的可以自行了解,这里我们只讲朴素 Min_25 筛。
把质数集记作
记
记
和
于是
接下来对各个部分分别求解。
Part 1
类似的手法,处理
质数单独计算贡献,合数则枚举最小因子
再注意到,若
而当
如上所述,我们可以写出递归代码。
cpp
Z F(ll u, int k) {
if (u <= primes[k])
return 0;
Z ret = sum[id(u)] - sum[primes[k]];
for (int i = k + 1; i < primes.size() && 1ll * primes[i] * primes[i] <= u; i++) {
ll pi = primes[i], pc = pi;
for (int c = 1; pc * pi <= u; c++, pc *= pi)
ret += fp(pi, c) * F(u / pc, i) + fp(pi, c + 1);
}
return ret;
}
Z F(ll u, int k) {
if (u <= primes[k])
return 0;
Z ret = sum[id(u)] - sum[primes[k]];
for (int i = k + 1; i < primes.size() && 1ll * primes[i] * primes[i] <= u; i++) {
ll pi = primes[i], pc = pi;
for (int c = 1; pc * pi <= u; c++, pc *= pi)
ret += fp(pi, c) * F(u / pc, i) + fp(pi, c + 1);
}
return ret;
}
Part 2
接下来,关键在于求
- 对于递归产生的
,总是有 。 - 对于递归产生的
,都是通过 的递推得到的,是 的不断整除。又有定理
这启发我们用整数分块,精简大于
我们只考虑
再联想到 Eratosthenes 筛法:每次枚举一个
容易发现,当
至此,我们完成了朴素 Min_25 筛的全部推导。
例题
LOJ6053 提示
因为
cpp
struct Min25 {
ll n, sn, m = 0;
vector<int> primes;
vector<Z> sum;
Z fp(int p, int k) {
return p ^ k;
}
int id(ll x) {
return x <= sn ? x : m - (n / x) + 1;
}
Min25(ll u) : n(u), sn(sqrt(n) + 1), sum(sn * 2 + 5) {
vector<bool> not_p(sn + 1);
vector<ll> w(sn * 2 + 5);
for (ll l = 1, r; l <= n; l = r + 1) {
w[++m] = r = n / (n / l);
}
vector<Z> s0(m + 1), s1(m + 1);
for (int i = 1; i <= m; i++) {
Z r = w[i] % P;
s0[i] = r - 1;
s1[i] = r * (r + 1) / 2 - 1;
}
primes.push_back(0);
for (int i = 2; i <= sn; i++) {
if (not not_p[i]) {
primes.push_back(i);
for (int j = i; j <= (sn - 1) / i; j++)
not_p[i * j] = true;
for (int j = m; w[j] >= 1ll * i * i; j--) {
s1[j] -= i * (s1[id(w[j] / i)] - s1[i - 1]);
s0[j] -= s0[id(w[j] / i)] - s0[i - 1];
}
}
}
for (int i = 2; i <= m; i++) {
sum[i] = s1[i] - s0[i] + 2;
}
}
Z eval() {
return F(n, 0) + 1;
}
Z F(ll u, int k) {
if (u <= primes[k])
return 0;
Z ret = sum[id(u)] - sum[primes[k]];
for (int i = k + 1; i < primes.size() && 1ll * primes[i] * primes[i] <= u; i++) {
ll pi = primes[i], pc = pi;
for (int c = 1; pc * pi <= u; c++, pc *= pi)
ret += fp(pi, c) * F(u / pc, i) + fp(pi, c + 1);
}
return ret;
}
};
struct Min25 {
ll n, sn, m = 0;
vector<int> primes;
vector<Z> sum;
Z fp(int p, int k) {
return p ^ k;
}
int id(ll x) {
return x <= sn ? x : m - (n / x) + 1;
}
Min25(ll u) : n(u), sn(sqrt(n) + 1), sum(sn * 2 + 5) {
vector<bool> not_p(sn + 1);
vector<ll> w(sn * 2 + 5);
for (ll l = 1, r; l <= n; l = r + 1) {
w[++m] = r = n / (n / l);
}
vector<Z> s0(m + 1), s1(m + 1);
for (int i = 1; i <= m; i++) {
Z r = w[i] % P;
s0[i] = r - 1;
s1[i] = r * (r + 1) / 2 - 1;
}
primes.push_back(0);
for (int i = 2; i <= sn; i++) {
if (not not_p[i]) {
primes.push_back(i);
for (int j = i; j <= (sn - 1) / i; j++)
not_p[i * j] = true;
for (int j = m; w[j] >= 1ll * i * i; j--) {
s1[j] -= i * (s1[id(w[j] / i)] - s1[i - 1]);
s0[j] -= s0[id(w[j] / i)] - s0[i - 1];
}
}
}
for (int i = 2; i <= m; i++) {
sum[i] = s1[i] - s0[i] + 2;
}
}
Z eval() {
return F(n, 0) + 1;
}
Z F(ll u, int k) {
if (u <= primes[k])
return 0;
Z ret = sum[id(u)] - sum[primes[k]];
for (int i = k + 1; i < primes.size() && 1ll * primes[i] * primes[i] <= u; i++) {
ll pi = primes[i], pc = pi;
for (int c = 1; pc * pi <= u; c++, pc *= pi)
ret += fp(pi, c) * F(u / pc, i) + fp(pi, c + 1);
}
return ret;
}
};
P5325 提示
注意到
cpp
struct Min25 {
ll n, sn, m = 0;
vector<int> primes;
vector<Z> sum;
Z fp(int p, int k) {
Z pk = Z(p).pow(k);
return pk * (pk - 1);
}
int id(ll x) {
return x <= sn ? x : m - (n / x) + 1;
}
Min25(ll u) : n(u), sn(sqrt(n) + 1), sum(sn * 2 + 5) {
vector<bool> not_p(sn + 1);
vector<ll> w(sn * 2 + 5);
for (ll l = 1, r; l <= n; l = r + 1) {
w[++m] = r = n / (n / l);
}
vector<Z> s2(m + 1), s1(m + 1);
for (int i = 1; i <= m; i++) {
Z r = w[i] % P;
s1[i] = r * (r + 1) / 2 - 1;
s2[i] = r * (r + 1) * (2 * r + 1) / 6 - 1;
}
primes.push_back(0);
for (int i = 2; i <= sn; i++) {
if (not not_p[i]) {
primes.push_back(i);
for (int j = i; j <= (sn - 1) / i; j++)
not_p[i * j] = true;
for (int j = m; w[j] >= 1ll * i * i; j--) {
s1[j] -= i * (s1[id(w[j] / i)] - s1[i - 1]);
s2[j] -= Z(i) * i * (s2[id(w[j] / i)] - s2[i - 1]);
}
}
}
for (int i = 2; i <= m; i++) {
sum[i] = s2[i] - s1[i];
}
}
Z eval() {
return F(n, 0) + 1;
}
Z F(ll u, int k) {
if (u <= primes[k])
return 0;
Z ret = sum[id(u)] - sum[primes[k]];
for (int i = k + 1; i < primes.size() && 1ll * primes[i] * primes[i] <= u; i++) {
ll pi = primes[i], pc = pi;
for (int c = 1; pc * pi <= u; c++, pc *= pi)
ret += fp(pi, c) * F(u / pc, i) + fp(pi, c + 1);
}
return ret;
}
};
struct Min25 {
ll n, sn, m = 0;
vector<int> primes;
vector<Z> sum;
Z fp(int p, int k) {
Z pk = Z(p).pow(k);
return pk * (pk - 1);
}
int id(ll x) {
return x <= sn ? x : m - (n / x) + 1;
}
Min25(ll u) : n(u), sn(sqrt(n) + 1), sum(sn * 2 + 5) {
vector<bool> not_p(sn + 1);
vector<ll> w(sn * 2 + 5);
for (ll l = 1, r; l <= n; l = r + 1) {
w[++m] = r = n / (n / l);
}
vector<Z> s2(m + 1), s1(m + 1);
for (int i = 1; i <= m; i++) {
Z r = w[i] % P;
s1[i] = r * (r + 1) / 2 - 1;
s2[i] = r * (r + 1) * (2 * r + 1) / 6 - 1;
}
primes.push_back(0);
for (int i = 2; i <= sn; i++) {
if (not not_p[i]) {
primes.push_back(i);
for (int j = i; j <= (sn - 1) / i; j++)
not_p[i * j] = true;
for (int j = m; w[j] >= 1ll * i * i; j--) {
s1[j] -= i * (s1[id(w[j] / i)] - s1[i - 1]);
s2[j] -= Z(i) * i * (s2[id(w[j] / i)] - s2[i - 1]);
}
}
}
for (int i = 2; i <= m; i++) {
sum[i] = s2[i] - s1[i];
}
}
Z eval() {
return F(n, 0) + 1;
}
Z F(ll u, int k) {
if (u <= primes[k])
return 0;
Z ret = sum[id(u)] - sum[primes[k]];
for (int i = k + 1; i < primes.size() && 1ll * primes[i] * primes[i] <= u; i++) {
ll pi = primes[i], pc = pi;
for (int c = 1; pc * pi <= u; c++, pc *= pi)
ret += fp(pi, c) * F(u / pc, i) + fp(pi, c + 1);
}
return ret;
}
};
P4213 提示
因为
cpp
struct Min25_phi {
ll n, sn, m = 0;
vector<int> primes;
vector<Z> sum;
Z fp(int p, int k) {
return qpow(p, k - 1) * (p - 1);
}
int id(ll x) {
return x <= sn ? x : m - (n / x) + 1;
}
Min25_phi(ll u) : n(u), sn(sqrt(n) + 1), sum(sn * 2 + 5) {
vector<bool> not_p(sn + 1);
vector<ll> w(sn * 2 + 5);
for (ll l = 1, r; l <= n; l = r + 1) {
w[++m] = r = n / (n / l);
}
vector<Z> s0(m + 1), s1(m + 1);
for (int i = 1; i <= m; i++) {
Z r = w[i];
s0[i] = r - 1;
s1[i] = r * (r + 1) / 2 - 1;
}
primes.push_back(0);
for (int i = 2; i <= sn; i++) {
if (not not_p[i]) {
primes.push_back(i);
for (int j = i; j <= (sn - 1) / i; j++)
not_p[i * j] = true;
for (int j = m; w[j] >= 1ll * i * i; j--) {
s1[j] -= i * (s1[id(w[j] / i)] - s1[i - 1]);
s0[j] -= s0[id(w[j] / i)] - s0[i - 1];
}
}
}
for (int i = 2; i <= m; i++) {
sum[i] = s1[i] - s0[i];
}
}
Z eval() {
return F(n, 0) + 1;
}
Z F(ll u, int k) {
if (u <= primes[k])
return 0;
Z ret = sum[id(u)] - sum[primes[k]];
for (int i = k + 1; i < primes.size() && 1ll * primes[i] * primes[i] <= u; i++) {
ll pi = primes[i], pc = pi;
for (int c = 1; pc * pi <= u; c++, pc *= pi) {
ret += fp(pi, c) * F(u / pc, i) + fp(pi, c + 1);
}
}
return ret;
}
};
struct Min25_mu {
ll n, sn, m = 0;
vector<int> primes;
vector<Z> sum;
Z fp(int p, int k) {
return -(k == 1);
}
int id(ll x) {
return x <= sn ? x : m - (n / x) + 1;
}
Min25_mu(ll u) : n(u), sn(sqrt(n) + 1), sum(sn * 2 + 5) {
vector<bool> not_p(sn + 1);
vector<ll> w(sn * 2 + 5);
for (ll l = 1, r; l <= n; l = r + 1) {
w[++m] = r = n / (n / l);
}
vector<Z> s0(m + 1);
for (int i = 1; i <= m; i++) {
Z r = w[i];
s0[i] = r - 1;
}
primes.push_back(0);
for (int i = 2; i <= sn; i++) {
if (not not_p[i]) {
primes.push_back(i);
for (int j = i; j <= (sn - 1) / i; j++)
not_p[i * j] = true;
for (int j = m; w[j] >= 1ll * i * i; j--) {
s0[j] -= s0[id(w[j] / i)] - s0[i - 1];
}
}
}
for (int i = 2; i <= m; i++) {
sum[i] = -s0[i];
}
}
Z eval() {
return F(n, 0) + 1;
}
Z F(ll u, int k) {
if (u <= primes[k])
return 0;
Z ret = sum[id(u)] - sum[primes[k]];
for (int i = k + 1; i < primes.size() && 1ll * primes[i] * primes[i] <= u; i++) {
ll pi = primes[i], pc = pi;
for (int c = 1; pc * pi <= u; c++, pc *= pi)
ret += fp(pi, c) * F(u / pc, i) + fp(pi, c + 1);
}
return ret;
}
};
struct Min25_phi {
ll n, sn, m = 0;
vector<int> primes;
vector<Z> sum;
Z fp(int p, int k) {
return qpow(p, k - 1) * (p - 1);
}
int id(ll x) {
return x <= sn ? x : m - (n / x) + 1;
}
Min25_phi(ll u) : n(u), sn(sqrt(n) + 1), sum(sn * 2 + 5) {
vector<bool> not_p(sn + 1);
vector<ll> w(sn * 2 + 5);
for (ll l = 1, r; l <= n; l = r + 1) {
w[++m] = r = n / (n / l);
}
vector<Z> s0(m + 1), s1(m + 1);
for (int i = 1; i <= m; i++) {
Z r = w[i];
s0[i] = r - 1;
s1[i] = r * (r + 1) / 2 - 1;
}
primes.push_back(0);
for (int i = 2; i <= sn; i++) {
if (not not_p[i]) {
primes.push_back(i);
for (int j = i; j <= (sn - 1) / i; j++)
not_p[i * j] = true;
for (int j = m; w[j] >= 1ll * i * i; j--) {
s1[j] -= i * (s1[id(w[j] / i)] - s1[i - 1]);
s0[j] -= s0[id(w[j] / i)] - s0[i - 1];
}
}
}
for (int i = 2; i <= m; i++) {
sum[i] = s1[i] - s0[i];
}
}
Z eval() {
return F(n, 0) + 1;
}
Z F(ll u, int k) {
if (u <= primes[k])
return 0;
Z ret = sum[id(u)] - sum[primes[k]];
for (int i = k + 1; i < primes.size() && 1ll * primes[i] * primes[i] <= u; i++) {
ll pi = primes[i], pc = pi;
for (int c = 1; pc * pi <= u; c++, pc *= pi) {
ret += fp(pi, c) * F(u / pc, i) + fp(pi, c + 1);
}
}
return ret;
}
};
struct Min25_mu {
ll n, sn, m = 0;
vector<int> primes;
vector<Z> sum;
Z fp(int p, int k) {
return -(k == 1);
}
int id(ll x) {
return x <= sn ? x : m - (n / x) + 1;
}
Min25_mu(ll u) : n(u), sn(sqrt(n) + 1), sum(sn * 2 + 5) {
vector<bool> not_p(sn + 1);
vector<ll> w(sn * 2 + 5);
for (ll l = 1, r; l <= n; l = r + 1) {
w[++m] = r = n / (n / l);
}
vector<Z> s0(m + 1);
for (int i = 1; i <= m; i++) {
Z r = w[i];
s0[i] = r - 1;
}
primes.push_back(0);
for (int i = 2; i <= sn; i++) {
if (not not_p[i]) {
primes.push_back(i);
for (int j = i; j <= (sn - 1) / i; j++)
not_p[i * j] = true;
for (int j = m; w[j] >= 1ll * i * i; j--) {
s0[j] -= s0[id(w[j] / i)] - s0[i - 1];
}
}
}
for (int i = 2; i <= m; i++) {
sum[i] = -s0[i];
}
}
Z eval() {
return F(n, 0) + 1;
}
Z F(ll u, int k) {
if (u <= primes[k])
return 0;
Z ret = sum[id(u)] - sum[primes[k]];
for (int i = k + 1; i < primes.size() && 1ll * primes[i] * primes[i] <= u; i++) {
ll pi = primes[i], pc = pi;
for (int c = 1; pc * pi <= u; c++, pc *= pi)
ret += fp(pi, c) * F(u / pc, i) + fp(pi, c + 1);
}
return ret;
}
};