第四节 杜教筛

Contents

核心柿子

我们要求积性函数 f 的前缀和。设:

S(n)=\sum_{i=1}^{n}f(i)

我们找到另一个积性函数 g,则有:

g(1)S(n)=\sum_{i=1}^{n}(f * g)(i)-\sum_{i=2}^{n}g(i)\cdot S\left(\left\lfloor\frac{n}{i}\right\rfloor\right)

如果能快速求出 f * gg 的前缀和,就可以数论分块求解 f 的前缀和。

一些好用的狄利克雷卷积结果

\begin{aligned}
\mu * I &= \varepsilon\cr \varphi * I &= if\cr d &= I * I\cr
\left(\varphi(i)\cdot i\right) * i &=\sum_{d|n}(\varphi(d)\cdot d)\cdot\frac{n}{d}=i^2\cr
\left(\varphi(i)\cdot i^2\right) * i^2 &=\sum_{d|n}(\varphi(d)\cdot d^2)\cdot\frac{n}{d^2}=i^3\cr
\left(\mu(i)\cdot i\right) * i &=\sum_{d|n}(\mu(d)\cdot d)\cdot\frac{n}{d}=i\cr
\left(\mu * id^2\right) * I &=\left(\mu * I\right) * id^2=\varepsilon * id^2=id^2
\end{aligned}

筛 mu 和 phi

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 5e6 + 50;
unordered_map<int, int> Summu;
unordered_map<int, ll> Sumphi;
int T, n;
int maxup;

ll phi[N], Sphi[N];
int mu[N], Smu[N];
int num[N], prime[N], tot;
void init(int n) {
    maxup = max(1e6, pow(n, 2.0/3.0));
    mu[1] = 1; phi[1] = 1;
    for (int i = 2; i < maxup; i++) {
        if (!num[i]) {
            prime[++tot] = i;
            mu[i] = -1;
            phi[i] = i - 1;
        }
        for (int j = 1, x; j <= tot && (x = i * prime[j]) < maxup; j++) {
            num[x] = 1;
            if (i % prime[j]) {
                mu[x] = -mu[i];
                phi[x] = phi[i] * phi[prime[j]];
            }
            else {
                phi[x] = phi[i] * prime[j];
                break;
            }
        }
    }
    //求前缀和
    for(int i = 1; i < maxup; i++) {
        Smu[i] = Smu[i-1] + mu[i];
        Sphi[i] = Sphi[i-1] + phi[i];
    }
}

int Get_Sum_mu(int x) {
    if (x < maxup) return Smu[x];
    if (Summu[x]) return Summu[x];
    int ret = 1; //卷积得到的\varepsilon前缀和为1
    for (int l = 2, r; l <= x; l = r + 1) {
        r = x / (x / l);
        ret -= (r - l + 1) * Get_Sum_mu(x / l);
        // 在l到r区间内I函数的和为r-l+1
    }
    return Summu[x] = ret;
}
ll Get_Sum_phi(int x) {
    if (x < maxup) return Sphi[x];
    if (Sumphi[x]) return Sumphi[x];
    ll ret = 1LL * x * (x + 1) / 2; // 卷积得到的id的前缀和
    for (int l = 2, r; l <= x; l = r+1) {
        r = x / (x / l);
        ret -= 1LL * (r - l + 1) * Get_Sum_phi(x / l) ;
    }
    return Sumphi[x] = ret;
}

int main() {
    init(INT_MAX);
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        printf("%lld %d\n", Get_Sum_phi(n), Get_Sum_mu(n));
    }
    return 0;
}

应用举例

简单例子

洛谷P3768 简单的数学题

题目大意:

\left(\sum_{i=1}^n\sum_{j=1}^n ij \gcd(i,j)\right) \bmod p

题目分析:

\begin{aligned}
原式&=\sum_dd\sum_{i=1}^n\sum_{j=1}^n ij [\gcd(i,j)=d]\cr
&=\sum_dd^3\sum_{i=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\sum_{j=1}^{\left\lfloor\frac{n}{d}\right\rfloor} ij [\gcd(i,j)=1]\cr
设g(n)&=1^3+2^3+\cdots+n^3=\frac{n^2(n+1)^2}{4}\cr
设f(n)&=\sum_{i=1}^n\sum_{j=1}^n ij [\gcd(i,j)=1]\cr
&=\sum_{i=1}^n\sum_{j=1}^n ij \sum_{d|\gcd(i,j)}\mu(d)\cr
&=\sum_{d=1}^{n}d^2\mu(d)\cdot g\left(\left\lfloor\frac{n}{d}\right\rfloor\right)
\end{aligned}

\begin{aligned}
\therefore 原式&=\sum_{d=1}^{n}d^3\cdot f\left(\left\lfloor\frac{n}{d}\right\rfloor\right)\cr
&=\sum_{d=1}^{n}d^3\sum_{x=1}^{\left\lfloor\frac{n}{d}\right\rfloor}x^2\mu(x)\cdot g\left(\left\lfloor\frac{n}{xd}\right\rfloor\right)\cr
\end{aligned}

观察到前两个和式顶部之积为 n,因此枚举 T=xd

\begin{aligned}
&=\sum_{T=1}^{n}g\left(\left\lfloor\frac{n}{T}\right\rfloor\right)T^2\sum_{x|T}^{T}\mu(x)\cdot \frac{T}{x}\cr
&=\sum_{T=1}^{n}g\left(\left\lfloor\frac{n}{T}\right\rfloor\right)\cdot T^2\varphi(T)
\end{aligned}

T^2\varphi(T) 可用杜教筛求前缀和,然后对整个柿子整除分块即可。

复杂例子

2019南京网络赛 E. K SUM

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇