Min_25. Learning notes

Prime prefix statistics

Find the sum of all prime numbers within \ (n \) to the power of \ (c \).

Consider the Ehrlich sieve, enumerate all multiples of it with a prime number at a time, and sieve out all illegal numbers.

Some definitions and explanations

  • \(P {\ min} (x) \): the minimum prime factor of \ (x \), \ (P {\ min} (1) = + \ infty \), if \ (x \) is not a prime number, then \ (P {\ min} (x) \ Le \ sqrt {x} \).
  • \The number of prime numbers within (m: \ left\lfloor \sqrt{n}\right\rfloor \).
  • \(p_k \): the \ (K \) prime number.
  • \(P_k \): the set composed of the first \ (K \) prime numbers.
  • \(S(n, k) \): the number within \ (n \) is the set of the remaining numbers after deleting the illegal number with the first \ (K \) prime number, that is \ (S(n, k) = \{x \in \mathbb{N}^* | x \le n \wedge p_{\min}(x) \ge p_k\}\). At the same time, we note that for \ (S(n, m) \) is all prime numbers that have not been traversed.
  • \(D(n, k) \): (D(n, k) = S(n, k - 1) - S(n, k) \) the set of numbers deleted by the prime number \ (k \) within \ (n \).
  • \(f(n, k) \): \ (\ displaystyle \ sum {x \ in S (n, K)} x ^ C \), so the answer to the question is \ (f(n, m) - 1 + \displaystyle \sum_{x \in P_m} x^c\).

Derivation process

\(S(n, k) = S(n, k - 1) - p_k S(\left\lfloor \frac{n}{p_k}\right\rfloor , k - 1)\)

That is, consider the number deleted by \ (p_k \), which can be proved by the fact that \ (p_k s (\ left \ lfloor \ frac{n}{p_k} \ right \ rfloor, K - 1) \) and \ (D(n, k) \) are bijective.

Therefore, we can get the formula of \ (f \):

\(f(n, k) = f(n, k - 1) - p_k^c f(\left\lfloor\frac{n}{p_k}\right\rfloor, k - 1)\)

If we directly use the above formula to calculate each prime number, there will be \ (\ frac {\ sqrt{n} {\ log n} \) prime numbers in total. According to the division and blocking, we actually need to calculate \ (\ sqrt{n} \), so the complexity is \ (\ mathcal O(\frac{n}{\log n}) \)!

We can consider optimization. We will notice that for \ (k > m \), \ (S(n, k) = S(n, k - 1) - \{p_k \} \), because \ (S \) is still changing, we have to calculate the values of those \ (k > m \). If we let \ (S \) not change, will there be some optimization?

We can define something new:

  • \(T(n, k) = S(n, k) +P_k\)
  • \(g(n, k) = f(n, k) + \displaystyle \sum_{x \in P_m} x^c \), and the final answer is \ (g(n, m) - 1 \)

So we can use the formula of \ (S \) to get:

\(T(n, k) = T(n, k - 1) - p_k \left(T(\left\lfloor \frac{n}{p_k}\right\rfloor , k - 1) - P_{k - 1}\right) + \{p_k\}\)

We also note that \ (T(p_k - 1, k - 1) \) is \ (P_{k - 1} + {1} \), so we can also get the formula of \ (g \):

\(g(n, k) = g(n, k - 1) - \left(g(\left\lfloor \frac{n}{p_k}\right\rfloor , k - 1) - g(p_k - 1, k - 1)\right)\)

As for \ (g(n, 0) = \sum_{i \le n} i^c \), which can be obtained by Lagrange interpolation in \ (\ mathcal O(c) \).

Then the complexity is \ (\ mathcal o (\ dfrac {n ^ {3 / 4} {\ log n}) \), which is not easy to prove.

Template tea: Luogu5493 prime prefix statistics

#define in read<int>()
#define lin read<ll>()
#define rep(i, x, y) for(int i = (x); i <= (y); i++)
#define per(i, x, y) for(int i = (x); i >= (y); i--)

using namespace std;

using ll = long long;

template < typename T > void chkmax(T &x, const T &y) { x = x > y ? x : y; }
template < typename T > void chkmin(T &x, const T &y) { x = x < y ? x : y; }

const int N = 1e6 + 10;
const int inf = 0x7fffffff;

int mod, C;
ll lim, n;

ll g0[N], g1[N];
// g0[i] is g(i), g1[i] is g(n / i)
ll qp(ll x, int t) { x %= mod; ll res = 1; for(; t; t = t >> 1, x = x * x % mod) if(t & 1) res = res * x % mod; return res; }

namespace calcg {
	const int N = 20;
	int y[N], fac[N], ifac[N], pre[N], suf[N], m;
	void init() {
		m = C + 2;
		fac[0] = 1; rep(i, 1, m) fac[i] = 1ll * fac[i - 1] * i % mod; 
                ifac[m] = qp(fac[m], mod - 2);
		per(i, m - 1, 0) ifac[i] = 1ll * ifac[i + 1] * (i + 1) % mod;
		rep(i, 1, m) y[i] = qp(i, C), y[i] = (y[i] + y[i - 1]) % mod;
	}
	int calc(ll v) {
		v %= mod;
		pre[0] = 1; rep(i, 1, m) pre[i] = 1ll * pre[i - 1] * (v - i + mod) % mod;
		suf[m + 1] = 1; per(i, m, 1) suf[i] = 1ll * suf[i + 1] * (v - i + mod) % mod;
		ll res = 0;
		rep(i, 1, m) {
			res += 1ll * pre[i - 1] * suf[i + 1] % mod * ifac[i - 1] % mod
                         * ifac[m - i] % mod * y[i] % mod * (m - i & 1 ? mod - 1 : 1) % mod;
			res %= mod;
		} return res;
	}
}

using calcg :: calc;

int main() {
	n = lin, C = in, mod = in, lim = sqrtl(n);
	calcg :: init();
	rep(i, 1, lim) g0[i] = (calc(i) - 1) % mod, g1[i] = (calc(n / i) - 1) % mod;
	rep(i, 2, lim) {
		g0[i] = (g0[i] + mod) % mod; if(g0[i] == g0[i - 1]) continue;
		ll pc = qp(i, C), pg = g0[i - 1];
		int l1 = lim / i, l2 = min(n / i / i, lim); chkmin(l1, l2);
		rep(j, 1, l1) g1[j] = (g1[j] - pc * (g1[j * i] - pg)) % mod;
		ll tt = n / i;
		if(tt < inf) { // Kachang
			int t = tt;
			rep(j, l1 + 1, l2) g1[j] = (g1[j] - pc * (g0[t / j] - pg)) % mod;
		} else {
			ll t = tt;
			rep(j, l1 + 1, l2) g1[j] = (g1[j] - pc * (g0[t / j] - pg)) % mod;
		}
		ll st = 1ll * i * i;
		per(j, lim, st) g0[j] = (g0[j] - pc * (g0[j / i] - pg)) % mod;
	}
	ll ans = 0;
	rep(i, 1, lim) {
		g1[i] = (g1[i] + mod) % mod;
		ans += 1ll * i * i % mod * g1[i] % mod; ans %= mod;
	} printf("%lld\n", ans);
	return 0;
}

Of course, this algorithm can make a wave of magic changes, and then you can do it LOJ6028 "from CommonAnts" prime count II Well, code.

Min_25 sieve

Give an integral function \ (F \):

  • \(F(p) \) is a simple polynomial about \ (p \).
  • \(F(p^k) \) can be obtained quickly.
  • Find \ (\ sum {I = 1} ^ n f (I) \).

Consider the number of \ (P {\ min} = k \) in the order of \ (K \) from large to small, then record \ (S(n, k) = \{x \in \mathbb{N}^* | x \le n \wedge p_{\min}(x) \ge p_k \} \), remember \ (f(n, k) = \sum_{x \in S(n, k)} F(x) \), and the final answer is \ (f(n, 1) \).

So there is \ (\ displaystyle f(n, k) = \sum_{i = k}^{p_i \le n} \sum_{v} F(p_i ^ v)f\left(\left\lfloor\frac{n}{p_i ^ v}\right\rfloor, k+ 1\right) \), when \ (p_i \ge \sqrt{n} \), the value of the latter formula is \ (F(p_i) \), so it can be solved with the prime prefix and prefix preprocessed before.

The complexity is \ (\ mathcal o (\ dfrac {n ^ {3 / 4} {\ log n}) \), which is unlikely to prove.

Better than the above \ (\ downarrow \)

#include <bits/stdc++.h>

#define in read<int>()
#define lin read<ll>()
#define rep(i, x, y) for(int i = (x); i <= (y); i++)
#define per(i, x, y) for(int i = (x); i >= (y); i--)

using namespace std;

using ll = long long;

const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int inv2 = (mod + 1) >> 1;
const int inv3 = (mod + 1) / 3;

ll n, lim, sp1[N], sp2[N], g1[N], g2[N], w[N];
int ind1[N], ind2[N], tot;
int pri[N / 10], pnum;
bool v[N];

void shai(int l) {
	rep(i, 2, l) {
		if(!v[i]) {
			pri[++pnum] = i;
			sp1[pnum] = (sp1[pnum - 1] + i) % mod;
			sp2[pnum] = (sp2[pnum - 1] + 1ll * i * i) % mod;
		}
		rep(j, 1, pnum) {
			if(pri[j] * i > l) break;
			v[pri[j] * i] = true; if(i % pri[j] == 0) break;
		}
	}
}

int S(ll x, int y) {
	if(x < pri[y]) return 0;
	ll res = 0;
	res += g2[x <= lim ? ind1[x] : ind2[n / x]] - sp2[y - 1];
	res -= g1[x <= lim ? ind1[x] : ind2[n / x]] - sp1[y - 1];
	res = (res % mod + mod) % mod;
	rep(k, y, pnum) {
		if(1ll * pri[k] * pri[k] > x) break;
		ll cur = pri[k];
		for(int c = 1; cur <= x; cur *= pri[k], c++) {
			res += cur % mod * ((cur - 1) % mod) % mod * (S(x / cur, k + 1) + (c != 1)) % mod;
			res %= mod;
		} // Enumerate the number of calculations, when c= When 1, it should include 1. When c = 1, we have calculated it.
	} return res % mod;
}

int main() {
	n = lin, lim = sqrtl(n);
	shai(lim * 2); // Sift a little more
	for(ll i = 1; i <= n; i++) {
		++tot, w[tot] = (n / i); ll v = w[tot] % mod;
		g1[tot] = (v * (v + 1) / 2 - 1) % mod;
		g2[tot] = (v * (v + 1) % mod * (v * 2 + 1) % mod * inv2 % mod * inv3 % mod - 1) % mod;
		if(w[tot] <= lim) ind1[w[tot]] = tot; else ind2[n / w[tot]] = tot;
		i = n / (n / i);
	}
	rep(i, 1, pnum) { 
		int p = pri[i]; ll x1 = sp1[i - 1], x2 = sp2[i - 1];
		rep(x, 1, tot) {
			if(1ll * p * p > w[x]) break;
			int y = w[x] / p <= lim ? ind1[w[x] / p] : ind2[n / (w[x] / p)];
			g1[x] = (g1[x] - 1ll * p * (g1[y] - x1) % mod + mod) % mod;
			g2[x] = (g2[x] - 1ll * p * p % mod * (g2[y] - x2) % mod + mod) % mod;
		}
	}
	printf("%d\n", (S(n, 1) + 1) % mod);
	return 0;
}

Keywords: Math

Added by adamh91 on Thu, 13 Jan 2022 06:03:51 +0200