M i n 25 Min25 Min25筛是一种能够用于求解积性函数 f ( x ) f(x) f(x)的前缀和的方法,其前提条件是 ∑ x ≤ n , x 是 质 数 f ( x ) \sum_{x\leq n,x是质数} f(x) ∑x≤n,x是质数f(x)可以用 ∑ x ≤ n , x 是 质 数 h ( x ) \sum_{x\leq n,x是质数} h(x) ∑x≤n,x是质数h(x)简单表示。其中 h ( x ) h(x) h(x)为完全积性函数。
首先,对于每一个 ⌊ n x ⌋ \lfloor \frac{n}{x} \rfloor ⌊xn⌋,我们求出 ∑ x ≤ n , x 是 质 数 h ( x ) \sum_{x\leq n,x是质数} h(x) ∑x≤n,x是质数h(x)。
设 p i p_i pi表示第 i i i小的质数, g ( N , i ) g(N,i) g(N,i)表示 ∑ x ≤ n , x 的 最 小 质 因 子 ≥ p i h ( x ) \sum_{x\leq n,x的最小质因子\geq p_i}h(x) ∑x≤n,x的最小质因子≥pih(x)。即 N N N以内的数进行 i i i轮埃氏筛后未被筛掉的数的 h ( x ) h(x) h(x)之和(质数未被删去),则所求即为 g ( N , ∣ P ∣ ) g(N,|P|) g(N,∣P∣)( ∣ P ∣ |P| ∣P∣为 ≤ n \leq n ≤n的质数个数)。
考虑如何由 g ( N , i − 1 ) g(N,i-1) g(N,i−1)得到 g ( N , i ) g(N,i) g(N,i)。考虑第 i i i轮埃氏筛所筛去的数。当 p i 2 > n p_i^2 > n pi2>n时,第 i i i轮不会筛去任何数。否则,将筛去最小质因子 ≥ p i \geq p_i ≥pi的合数,所以
g ( N , i ) = g ( N , i − 1 ) − h ( p i ) × ( g ( ⌊ N p i ⌋ , i − 1 ) − ∑ j = 1 i − 1 h ( p i ) ) g(N,i)=g(N,i-1)-h(p_i)\times(g(\lfloor \frac {N} {p_i}\rfloor,i-1)-\sum_{j=1}^{i-1}h(p_i)) g(N,i)=g(N,i−1)−h(pi)×(g(⌊piN⌋,i−1)−j=1∑i−1h(pi))
因为 p i 2 ≤ N p_i^2\leq N pi2≤N,所以 p i ≤ ⌊ N p i ⌋ p_i \leq \lfloor \frac {N} {p_i}\rfloor pi≤⌊piN⌋,所以 ≤ p i \leq p_i ≤pi的质数也会被包含在 g ( ⌊ N p i ⌋ , i − 1 ) g(\lfloor \frac {N} {p_i}\rfloor,i-1) g(⌊piN⌋,i−1)里,要加回来。
综上,
g ( N , i ) = { g ( N , i − 1 ) p i 2 > n g ( N , i − 1 ) − h ( p i ) × ( g ( ⌊ N p i ⌋ , i − 1 ) − ∑ j = 1 i − 1 h ( p i ) ) p i 2 ≤ n g(N,i)=\begin{cases} g(N,i-1)&p_i^2\gt n\\ g(N,i-1)-h(p_i)\times(g(\lfloor \frac {N} {p_i}\rfloor,i-1)-\sum_{j=1}^{i-1}h(p_i))&p_i^2\le n\end{cases} g(N,i)={g(N,i−1)g(N,i−1)−h(pi)×(g(⌊piN⌋,i−1)−∑j=1i−1h(pi))pi2>npi2≤n
这部分的时间复杂度是 O ( N 3 4 l o g N ) O(\frac {N^{\frac {3} {4}}} {log \ \ N}) O(log NN43)
接下来考虑如何用上述信息求 ∑ i = 1 n f ( x ) \sum_{i=1}^n f(x) ∑i=1nf(x)。
设 s ( N , i ) s(N,i) s(N,i)表示 ∑ j = 1 , j 的 最 小 质 因 子 ≥ p i n f ( j ) \sum_{j=1,j的最小质因子\geq p_i}^n f(j) ∑j=1,j的最小质因子≥pinf(j)。
由定义最终答案为 s ( N , 1 ) + f ( 1 ) s(N,1)+f(1) s(N,1)+f(1)。
经过上面的计算,我们已经可以快速计算 ∑ x ≤ n , x 是 质 数 f ( x ) \sum_{x\leq n,x是质数} f(x) ∑x≤n,x是质数f(x)。
考虑合数的贡献,枚举质因子个数及其出现次数,因为 f ( x ) f(x) f(x)为积性函数,所以贡献为
∑ j ≥ i p j 2 ≤ N ∑ e = 1 p j e + 1 ≤ N s ( ⌊ N p i ⌋ , j + 1 ) × f ( p i e ) + f ( p i e + 1 ) \sum_{j\geq i}^{p_j^2 \leq N}\sum_{e=1}^{p_j^{e+1}\leq N} s(\lfloor \frac {N} {p_i}\rfloor,j+1)\times f(p_i^e)+f(p_i^{e+1}) j≥i∑pj2≤Ne=1∑pje+1≤Ns(⌊piN⌋,j+1)×f(pie)+f(pie+1)
综上,
s ( N , i ) = { 0 p i > n ∑ j ≥ i p j 2 ≤ N ∑ e = 1 p j e + 1 ≤ N s ( ⌊ N p i ⌋ , j + 1 ) × f ( p i e ) + f ( p i e + 1 ) + ∑ x ≤ n , x 是 质 数 f ( x ) − ∑ j = 1 i − 1 f ( p i ) p i ≤ n s(N,i)=\begin{cases} 0&p_i\gt n\\ \sum_{j\geq i}^{p_j^2 \leq N}\sum_{e=1}^{p_j^{e+1}\leq N} s(\lfloor \frac {N} {p_i}\rfloor,j+1)\times f(p_i^e)+f(p_i^{e+1})+\sum_{x\leq n,x是质数} f(x)-\sum_{j=1}^{i-1}f(p_i)&p_i \le n\end{cases} s(N,i)={0∑j≥ipj2≤N∑e=1pje+1≤Ns(⌊piN⌋,j+1)×f(pie)+f(pie+1)+∑x≤n,x是质数f(x)−∑j=1i−1f(pi)pi>npi≤n
这部分的时间复杂度不用记忆化也很快,是 O ( N 3 4 l o g N ) O(\frac {N^{\frac {3} {4}}} {log \ \ N}) O(log NN43)。
LOJ6053
考虑如何用 ∑ x ≤ , n x 是 质 数 h ( x ) \sum_{x\leq,nx是质数} h(x) ∑x≤,nx是质数h(x)表示 ∑ x ≤ , n x 是 质 数 f ( x ) \sum_{x\leq,nx是质数} f(x) ∑x≤,nx是质数f(x)。
可以发现,对于质数 p p p
f ( p ) = { p + 1 p = 2 p − 1 p ≠ 2 f(p)=\begin{cases} p+1 & p=2 \\ p-1 & p \neq 2\end{cases} f(p)={p+1p−1p=2p̸=2
所以,当 i > 1 i>1 i>1时, ∑ x ≤ n , x 是 质 数 f ( x ) − ∑ j = 1 i f ( p i ) \sum_{x\leq n,x是质数} f(x)-\sum_{j=1}^if(p_i) ∑x≤n,x是质数f(x)−∑j=1if(pi)实际计算了 x x x以内质数的和减去减去质数的个数,筛单位函数与恒等函数即可。当 i = 1 i=1 i=1时,给答案加上 2 2 2即可。
#include
using namespace std;
#define int long long
typedef long long lint;
const int maxn = 200005, mod = 1e9 + 7, inv2 = (mod + 1) / 2;
lint n, w[maxn];
int m, S;
int id1[maxn], id2[maxn];
int vis[maxn], p[maxn], sum[maxn], tot;
int h[maxn], g[maxn];
inline lint gi()
{
char c = getchar();
while (c < '0' || c > '9') c = getchar();
lint sum = 0;
while ('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
return sum;
}
void pre(int n)
{
for (int i = 2; i <= n; ++i) {
if (!vis[i]) p[++tot] = i, sum[tot] = sum[tot - 1] + i;
for (int j = 1; i * p[j] <= n; ++j) {
vis[i * p[j]] = 1;
if (i % p[j] == 0) break;
}
}
}
int s(int x, int i)
{
if (x <= 1 || p[i] > x) return 0;
int k = x <= S ? id1[x] : id2[n / x];
int res = ((g[k] - h[k] - (sum[i - 1] - (i - 1))) % mod + mod) % mod;
if (i == 1) res += 2;
lint p1, p2;
for (int j = i; j <= tot && (lint)p[j] * p[j] <= x; ++j){
p1 = p[j]; p2 = p1 * p[j];
for (lint e = 1; p2 <= x; p1 = p2, p2 *= p[j], ++e) {
res += ((lint)s(x / p1, j + 1) * (p[j] ^ e) + (p[j] ^ (e + 1))) % mod;
if (res >= mod) res -= mod;
}
}
return res;
}
signed main()
{
n = gi(); S = sqrt(n);
pre(S);
for (lint i = 1, j; i <= n; i = j + 1) {
j = n / (n / i);
w[++m] = n / i;
if (w[m] <= S) id1[w[m]] = m;
else id2[n / w[m]] = m;
h[m] = (w[m] - 1) % mod;
g[m] = (lint)(w[m] + 2) % mod * ((w[m] - 1) % mod) % mod * inv2 % mod;
}
for (int j = 1; j <= tot; ++j)
for (int i = 1; i <= m && (lint)p[j] * p[j] <= w[i]; ++i) {
int k = (w[i] / p[j] <= S) ? id1[w[i] / p[j]] : id2[n / (w[i] / p[j])];
h[i] = ((lint)h[i] - h[k] + j - 1 + mod) % mod;
g[i] = (g[i] - (lint)p[j] * (g[k] - sum[j - 1]) % mod + mod) % mod;
}
printf("%lld\n", s(n, 1) + 1);
return 0;
}