杜教筛

积性函数

如果一个数论函数(f(n)),满足(n,m)互质,那么有(f(n*m) = f(n)*f(m)),那么(f(n))为积性函数

特别地,如果对于任意(n,m)都满足(f(n*m) = f(n)*f(m)),那么(f(n))为完全积性函数

常见的积性函数有

积性函数

狄利克雷卷积

对于两个积性函数(f(n),g(n)),定义它们的狄利克雷卷积为:((f*g)(n) = sum_{d|n} f(d) * g(frac{n}{d}))

常用的几种卷积关系:

$mu * 1 = epsilon $

(phi * 1=Idquad quadvarphi = Id * mu)

(d = 1 * 1quad quad 1 = mu*d)

杜教筛

以低于线性的时间复杂度计算积性函数前缀和

假设要求的积性函数(f)的前缀和为(S)

构造两个辅助函数:积性函数(g),狄利克雷卷积(f*g)

有结论(sum_{i = 1}^n(f*g)(i) = sum_{i = 1}^ng(i)S(frac{n}{i}))

变式:

[g(1)S(n) = sum_{i = 1}^n(f*g)(i) - sum_{i = 2}^ng(i)S(frac{n}{i}) ]

只需要找到一个(g(n))使得(sum_{i = 1}^n(f*g)(i))可以被快速计算,且(g(n))的前缀和容易求

那么可以分块+递归求出(S(n))

莫比乌斯函数前缀和

(S(n) = sum_{i= 1}^nmu(i))

(g(1)S(n) = sum_{i = 1}^n(f*g)(i) - sum_{i = 2}^ng(i)S(frac{n}{i}))

选择(g = 1(i)),那么对于((f*g)(i) = sum_{d|i}1*mu(frac{i}{d}) = epsilon)

(sum_{j|i}mu(j)= left{egin{array}{ll} 0 & i geq 2 \ 1 & i=1 end{array} ight.)

(S(n) = 1 - sum_{i = 2}^nS(lfloorfrac{n}{i} floor))

欧拉函数前缀和

(S(n) = sum_{i = 1}^nvarphi(i))

(g(1)S(n) = sum_{i = 1}^n(f*g)(i) - sum_{i = 2}^ng(i)S(frac{n}{i}))

选择(g = 1(i)),那么对于((f*g)(i) = sum_{d|i}1 * varphi(frac{i}{d}) = Id)

(sum_{i = 1}^nId = frac{n(n+1)}{2})

(S(n) = frac{n(n+1)}{2} - sum_{i=2}^nS(lfloorfrac{n}{i} floor))

模板

#include <iostream>
#include <cstdio>
#include <unordered_map>
#define ll long long
using namespace std;
const int N = 3e6+5;
bool vis[N];
ll phi[N + 5];
ll mu[N + 5], pri[N];
int tot = 0;
unordered_map<int,ll>ans_p,ans_m;
void table(int N){
    mu[1] = 1,phi[1] = 1;vis[1] = 1;
    for(int i = 2; i <= N; i++){
        if(!vis[i]){
            pri[++tot] = i;
            mu[i] = -1;phi[i] = i - 1;
        }
        for(int j = 1; j <= tot; j++){
            if(i * pri[j] > N)break;
            vis[i * pri[j]] = 1;
            if(i % pri[j] == 0){
                mu[i * pri[j]] = 0;
                phi[i * pri[j]] = phi[i] * pri[j];
                break;
            }else{
                mu[i * pri[j]] = -mu[i];
                phi[i * pri[j]] = phi[i] * phi[pri[j]];
            }
        }
    }
    for(int i = 1; i <= N; i++){
        phi[i] += phi[i - 1];
        mu[i] += mu[i - 1];
    }
}
ll sum_p(int n){
    if(n <= N)return phi[n];
    if(ans_p[n])return ans_p[n];
    ll ans = (ll)n * (n + 1)/2;
    for(int l = 2,r; l <= n; l = r + 1){
        r = n/(n/l);
        ans -= sum_p(n/l) * (r - l + 1);
    }
    return ans_p[n] = ans;
}
ll sum_m(int n){
    if(n <= N)return mu[n];
    if(ans_m[n])return ans_m[n];
    ll ans = 1;
    for(int l = 2,r; l <= n; l = r + 1){
        r = n/(n/l);
        ans -= sum_m(n/l) * (r - l + 1);
    }
    return ans_m[n] = ans;
}
int main(){
    table(N);
    int n;
    scanf("%d",&n);
    printf("%lld %lld
", sum_m(n),sum_p(n));
    return 0;
}

mini筛

原文地址:https://www.cnblogs.com/Emcikem/p/12251924.html