杜教筛 [学习笔记]【更新中】

感情迁移 提交于 2019-12-26 03:44:10

杜教筛

嘟嘟嘟


tangjz orz

jiry_2 orz

任之洲 2016国家队论文 orz


概述

前置技能:莫比乌斯反演

可以在\(O(\frac{3}{4})\)\(O(\frac{2}{3})\)复杂度完成数论函数(前缀和)的计算

一般形式

数论函数\(f(n)\),求
\[ S(n) = \sum_{i=1}^n f(i) \]

对于任意数论函数\(g(n)\),均满足

\[ \sum_{i=1}^n (f*g)(i) = \sum_{i=1}^n g(i)S(\lfloor \frac{n}{i} \rfloor) \]

\(Proof.\)

\[ \begin{align*} \sum_{i=1}^n (f*g)(i) &= \sum_{i=1}^n \sum_{d\mid i} f(d) g(\frac{i}{d}) \\ 先枚举几倍再枚举约数 \\ &= \sum_{i=1}^n g(i) \sum_{d=1}^{\lfloor \frac{n}{d} \rfloor}f(d) \\ &= \sum_{i=1}^n g(i) S(\lfloor \frac{n}{d} \rfloor) \end{align*} \]

  • 注意枚举几倍的技巧:对于i*j=k,我们枚举了i和j

这样的话可以得到
\[ g(1)S(n) = \sum_{i=1}^n (f*g)(i) - \sum_{i=2}^n g(i)S(\lfloor \frac{n}{i} \rfloor) \]
通常情况\(g(1)=1\)

这个柿子可以整除分块

找到合适的\(g\)

如果能通过狄利克雷卷积构造一个更好计算前缀和的函数,且用于卷积的另一个函数也易计算,则可以简化计算过程

时间复杂度

假设计算出\(ϕ(n)\)的复杂度为\(T(n)\),则有\(T(n)=O(\sqrt{n})+\sum_{i=1}^{\sqrt{n}}{T(i)+T(\frac{n}{i})}\)这里只展开一层就可以了,更深层的复杂度是高阶小量,所以有\(T(n)=\sum_{i=1}^{\sqrt{n}}{O(\sqrt{i})+O(\sqrt{\frac{n}{i}})}=O(n^\frac{3}{4})\)

预处理前k个的答案后,\(T(n)=\sum_{i=1}^{\frac{n}{k}}{\sqrt{\frac{n}{i}}}=O(\frac{n}{\sqrt{k}})\),\(k=O(n^\frac{2}{3})\)时最优\(T(n)=O(n^\frac{2}{3})\)

基本形式

  • 基本形式只是为了简化思考,用一般形式找函数卷上均可以完成
  • 就是说没大有用啦

一. 数论函数\(f(n)\),完全积性函数\(g(n)\),求
\[ S(n)=\sum_{i=1}^n(f \cdot g)(i) \]
此时满足
\[ \sum_{i=1}^n {((f*1) \cdot g)(i)} = \sum_{i=1}^n g(i)S(\lfloor \frac{n}{i} \rfloor) \]
\(Proof.\)
\[ \begin{align*} \sum_{i=1}^n {((f*1) \cdot g)(i)} &= \sum_{i=1}^n g(i) \sum_{d\mid i} f(d) \\ 先枚举几倍 \\ &= \sum_{i=1}^n \sum_{d=1}^{\lfloor \frac{n}{i} \rfloor} f(d) g(id) \\ 因为g(id)=g(i)\cdot g(d) \\ &= \sum_{i=1}^n g(i) S(\lfloor \frac{n}{d} \rfloor) \end{align*} \]
也就是说这种情况我们只要让另一个函数卷\(1\),完全积性函数直接当做我们找的函数。

二. 待填坑


简单的栗子

都是卷上\(1\)

一. 求\(\mu\)的前缀和
\[ \mu * 1 = \epsilon \\ S(n) = 1 - \sum_{i=2}^n S(\lfloor \frac{n}{i} \rfloor) \]
二. 求\(\varphi\)的前缀和
\[ \phi * 1 = id \\ S(n) = \frac{n(n+1)}{2} - \sum_{i=2}^n S(\lfloor \frac{n}{i} \rfloor) \]

代码实现

使用记忆化搜索和哈希表

//这是phi前缀和。首先要线性筛预处理一部分。
namespace ha {
    const int p = 1001001;
    struct meow{int ne; ll val, r;} e[3000];
    int cnt=1, h[p];
    inline void insert(ll x, ll val) {
        ll u = x % p;
        for(int i=h[u];i;i=e[i].ne) if(e[i].r == x) return;
        e[++cnt] = (meow){h[u], val, x}; h[u] = cnt;
    }
    inline ll quer(ll x) {
        ll u = x % p;
        for(int i=h[u];i;i=e[i].ne) if(e[i].r == x) return e[i].val;
        return -1;
    }
} using ha::insert; using ha::quer;

ll dj_sieve(ll n) {
    if(n <= U) return phi[n];
    if(quer(n) != -1) return quer(n);
    ll ans = n%mo * ((n+1) %mo) %mo * inv2 %mo, r;
    for(ll i=2; i<=n; i=r+1) {
        r = n/(n/i);
        mod(ans -= dj_sieve(n/i) * ((r-i+1) %mo) %mo);
    }
    insert(n, ans);
    return ans;
}

栗子

一. 求 \(\sum_{i=1}^n \sum_{j=1}^n lcm(i, j)\)

有两类做法。

一.变成积性函数求和的形式

首先进行化简
\[ \begin{align*} A(n) &= \sum_{i=1}^nlcm(i,n)=n \sum_{i=1}^n\frac{i}{(n,i)} \\ &=n \sum_{d\mid n}\sum_{i=1}^{\lfloor \frac{n}{d} \rfloor}i[(\frac{n}{d}, i)=1] \\ &= \frac{1}{2} n (1 + \sum_{d\mid n}d \cdot \varphi(d)) \end{align*} \]
\(ans = 2*A(n) - \sum_{i=1}^n\)

就是\(f(n) = n\sum_{d\mid n}d \cdot \varphi(d)= id \cdot ((id \cdot \varphi) * 1)\)的前缀和。

  • 其中重要的一步在于使用欧拉函数的性质代入,而不是使用莫比乌斯函数代入

这里又有两种做法。

法一:
\[ \begin{align*} ans &= \sum_{i=1}^n i \sum_{d\mid i}d \cdot \varphi(d) \\ 先枚举几倍 \\ &= \sum_{i=1}^n i \sum_{d=1}^{\lfloor \frac{n}{i} \rfloor} d^2 \cdot \varphi(d) \end{align*} \]
后面是可以整除分块的形式,我们只要处理出\(i^2 \cdot \varphi(i)=(id^2 \cdot \varphi)(i)\)的前缀和\(S(n)\)就行了

\(id^2\)是完全积性函数,满足杜教筛基本形式一,单独让\(\varphi\)卷上\(1\),也变成\(id\)了。

或者直接卷上\(id^2\),效果相同
\[ S(n) = \sum_{i=1}^n i^3 - \sum_{i=2}^n i^2 S(\lfloor \frac{n}{i} \rfloor) \]
其中\(\sum_{i=1}^{n} i^3 = (\frac{n(n+1)}{2})^2,\ \sum_{i=1}^{n} i^2 = \frac{n(n+1)(2n+1)}{6}\)

杜教筛的过程中计算了所有\(S(\lfloor \frac{n}{i} \rfloor)\),可以和整除分块配合食用

法二:

把f外面的n拿进来

直接计算\(f(n) = id \cdot ((id \cdot \varphi) * 1) = (id^2 \cdot \varphi) * id\)的前缀和。

卷上\(id^2\)
\[ ((id^2 \cdot \varphi) * id^2) * id = id^3 * id \\ S(n) = \sum_{i=1}^n (id^3 * id)(i) - \sum_{i=2}^n i^2 S(\lfloor \frac{n}{i} \rfloor) \]
前部分的前缀和可以用整除分块解决

使用线性筛直接预处理S的前\(n^{\frac{2}{3}}\)项,只要预处理\((id \cdot \varphi) * 1 = \sum_{d\mid n}d \cdot \varphi(d)\)就行了,因为是点乘比较好做。\(p^c\)的形式处理出来,剩下的保留最小质因子的幂次然后用积性。

二.使用莫比乌斯反演的套路

abclzr的博客发现了这种做法:

套路推♂倒之后得到的柿子是:
\[ \sum_{i=1}^n \frac{\lfloor \frac{n}{i} \rfloor(\lfloor \frac{n}{i} \rfloor+1)}{2} \frac{\lfloor \frac{m}{i} \rfloor(\lfloor \frac{m}{i} \rfloor+1)}{2} i \sum_{d\mid i} d\cdot \mu(d) \]
我们只需用杜教筛计算\(i \sum_{d\mid i} d\cdot \mu(d)\)的前缀和,然后与整除分块配合就行了(因为每次块的r的值也是一个\(\frac{n}{i}\)的值)

就是要计算\(f=(id^2 \cdot \mu) * id\)的前缀和,卷上\(id^2\)后变成\(f(n) = n\sum_{d\mid n}[d=1]=n\)

上杜教筛就行了

预处理的话,可以用线性筛预处理\(f'=\sum_{d\mid n}d\cdot \mu(d)\),发现\(f'=\prod_i(1-p_i)\)

这样做的好处是可以处理n和m的情况


总结

找到一个函数卷上方便求

莫比乌斯反演的题目一般是约数和倍数互换 令D=de,这里一般是约数与几倍互换

TA:

对于d,e,D=d*e 三项贡献的这种,可以枚举D将其化为狄利克雷卷积,也可以枚举d和e化成带下取整的式子;一般来讲前者往往易于预处理,可以应付多组询问,后者则在单次询问中有优秀表现。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!