杜教筛
杜教筛可以在 O ( n 2 3 ) O(n ^{\frac{2}{3}}) O(n32) 的复杂度内求解积性函数的前缀和
设数论函数 f ( x ) f(x) f(x),求
∑ i = 1 n f ( i ) \sum_{i=1}^{n}f(i) i=1∑nf(i)
令 S ( n ) = ∑ i = 1 n f ( i ) S(n) = \sum \limits_{i=1} ^{n} f(i) S(n)=i=1∑nf(i),找一个数论函数 g ( x ) g(x) g(x) 与 f ( x ) f(x) f(x) 做卷积
∑ i = 1 n f ∗ g = ∑ i = 1 n g ∗ f \sum_{i=1} ^ {n} f * g = \sum_{i=1} ^{n}g *f i=1∑nf∗g=i=1∑ng∗f
展开卷积
∑ i = 1 n ∑ d ∣ i g ( d ) f ( i d ) \sum_{i=1}^{n} \sum_{d \mid i}g(d)f(\frac{i}{d}) i=1∑nd∣i∑g(d)f(di)
交换求和次序
∑ d = 1 n g ( d ) ∑ i = 1 ⌊ n d ⌋ f ( i ) \sum_{d=1} ^{n}g(d) \sum_{i=1}^{\lfloor\frac{n}{d} \rfloor} f(i) d=1∑ng(d)i=1∑⌊dn⌋f(i)
后半部分其实就是 S ( ⌊ n d ⌋ ) S(\lfloor\dfrac{n}{d} \rfloor) S(⌊dn⌋),换一下变量名得
∑ i = 1 n g ( i ) S ( ⌊ n i ⌋ ) \sum_{i=1} ^{n}g(i)S(\lfloor\frac{n}{i} \rfloor) i=1∑ng(i)S(⌊in⌋)
那么就有递推公式
g ( 1 ) S ( n ) = ∑ i = 1 n f ∗ g − ∑ i = 2 n g ( i ) S ( ⌊ n i ⌋ ) g(1)S(n) = \sum_{i=1} ^{n}f*g-\sum_{i=2}^{n} g(i)S(\lfloor\frac{n}{i} \rfloor) g(1)S(n)=i=1∑nf∗g−i=2∑ng(i)S(⌊in⌋)
假设 ∑ i = 1 n f ∗ g \sum\limits _{i=1} ^{n}f*g i=1∑nf∗g 可以快速求出,后半部分则可以用数论分块求解
莫比乌斯函数前缀和
由狄利克雷卷积
ε = μ ∗ I \varepsilon = \mu * I ε=μ∗I
设 h = ε , f = μ , g = I h=\varepsilon,f=\mu,g=I h=ε,f=μ,g=I 套用杜教筛
S ( n ) = ∑ i = 1 n ε ( i ) − ∑ i = 2 n I ( i ) S ( ⌊ n i ⌋ ) S(n) = \sum_{i=1} ^{n}\varepsilon(i)-\sum_{i=2}^{n} I(i)S(\lfloor\frac{n}{i} \rfloor) S(n)=i=1∑nε(i)−i=2∑nI(i)S(⌊in⌋)
化简可得
S ( n ) = 1 − ∑ i = 2 n S ( ⌊ n i ⌋ ) S(n) = 1 - \sum_{i=2}^{n} S(\lfloor\frac{n}{i} \rfloor) S(n)=1−i=2∑nS(⌊in⌋)
欧拉函数前缀和
法一:
先对欧拉函数用莫比乌斯反演
∑ i = 1 n φ ( i ) \sum_{i=1} ^{n}\varphi(i) i=1∑nφ(i)
展开欧拉函数
∑ i = 1 n ∑ j = 1 n [ gcd ( i , j ) = 1 ] \sum_{i=1} ^{n} \sum_{j = 1} ^{n} [\gcd(i,j)=1] i=1∑nj=1∑n[gcd(i,j)=1]
莫比乌斯反演
∑ i = 1 n ∑ j = 1 n ∑ d ∣ gcd ( i , j ) μ ( d ) \sum_{i=1}^{n} \sum_{j = 1} ^{n} \sum_{d \mid \gcd(i,j)}\mu(d) i=1∑nj=1∑nd∣gcd(i,j)∑μ(d)
交换求和次序
∑ d = 1 n μ ( d ) ⌊ n d ⌋ 2 \sum_{d=1} ^{n}\mu(d) \lfloor \frac{n}{d} \rfloor ^2 d=1∑nμ(d)⌊dn⌋2
那么就可以用前面的莫比乌斯函数前缀和来求解了
注意要减去 i = 1 , j = 1 i=1,j=1 i=1,j=1 的情况,并且 / 2 /2 /2
法二:
由狄利克雷卷积
I d = φ ∗ I Id = \varphi * I Id=φ∗I
设 h = I d , f = φ , g = I h = Id,f=\varphi,g=I h=Id,f=φ,g=I 套用杜教筛
S ( n ) = ∑ i = 1 n I d ( i ) − ∑ i = 2 n I ( i ) S ( ⌊ n i ⌋ ) S(n) = \sum_{i=1} ^{n}Id(i)-\sum_{i=2}^{n} I(i)S(\lfloor\frac{n}{i} \rfloor) S(n)=i=1∑nId(i)−i=2∑nI(i)S(⌊in⌋)
S ( n ) = ∑ i = 1 n i − ∑ i = 2 n S ( ⌊ n i ⌋ ) S(n) = \sum_{i=1} ^{n}i-\sum_{i=2}^{n} S(\lfloor\frac{n}{i} \rfloor) S(n)=i=1∑ni−i=2∑nS(⌊in⌋)
等差数列求和
S ( n ) = n ( n + 1 ) 2 − ∑ i = 2 n S ( ⌊ n i ⌋ ) S(n) = \frac{n (n + 1)}{2} - \sum_{i=2}^{n} S(\lfloor\frac{n}{i} \rfloor) S(n)=2n(n+1)−i=2∑nS(⌊in⌋)
代码(两个函数一起求):
题目:洛谷P4213
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e6 + 5;
int T, n, mobius[N], primes[N], cnt, sum[N];
bool st[N];
unordered_map<int, int> mp;
void get_mobius(int n) {
mobius[1] = 1;
for (int i = 2; i <= n; i ++) {
if (!st[i]) {
primes[cnt ++] = i;
mobius[i] = -1;
}
for (int j = 0; primes[j] * i <= n; j ++) {
int t = primes[j] * i;
st[t] = 1;
if (i % primes[j] == 0) {
mobius[t] = 0;
break;
}
mobius[t] = -mobius[i];
}
}
for (int i = 1; i <= n; i ++) sum[i] = sum[i - 1] + mobius[i];
}
int sum_mobius(int n) {
if (n < N) return sum[n];
if (mp[n]) return mp[n];
int res = 1;
for (int l = 2, r; l <= n; l = r + 1) {
r = n / (n / l);
res -= sum_mobius(n / l) * (r - l + 1);
}
return mp[n] = res;
}
int sum_phi(int n) {
int res = 0;
for (int l = 1, r; l <= n; l = r + 1) {
r = n / (n / l);
res += (sum_mobius(r) - sum_mobius(l - 1)) * (n / l) * (n / l);
}
return (res - 1) / 2 + 1;
}
signed main() {
get_mobius(N - 1);
cin >> T;
while (T --) {
cin >> n;
cout << sum_phi(n) << " " << sum_mobius(n) << endl;
}
}