杜教筛

杜教筛

前置:数论分块莫比乌斯反演狄利克雷卷积欧拉函数
对于数论函数 f(n),杜教筛能够在线性的时间复杂度内求得 i=1nf(i) 的值。
只要我们能够构造出另一个数论函数 g(n),使得 i=1n(fg)(i) 能够以较快的时间复杂度求得,我们便能够使用杜教筛求得 i=1nf(i) 的值。
我们设 S(n)=i=1nf(i),我们则需要考虑构造出一个与 S(n) 有关的式子。

对于 i=1n(fg)(i),有,

i=1n(fg)(i)=i=1nd|ig(d)f(id)

注意此处我们将 i=1n(fg)(i) 使用狄利克雷卷积展开为 g(d)f(id) 而非 f(d)g(id) 的原因是为了构造出 S
枚举 d,转换一下式子得,

d=1ni=1ndg(d)f(i)

g(d) 提出来,

d=1ng(d)i=1ndf(i)

根据 S(n) 的定义,后面这块式子可以变为 S(nd)

d=1ng(d)S(nd)

为了构造 S(n),我们把 d=1 时的式子拆开来

g(1)S(n)+i=2ng(i)S(ni)

移项可得:

g(1)S(n)=i=1n(fg)(i)i=2ng(i)S(ni)

那么,对于 f(n),我们只要找到一个合适的数论函数 g(n) 便能够求解 S(n)

莫比乌斯函数

莫比乌斯函数,即 μ(n)

我们令 g(n)=1

S(n)=i=1nd|iμ(d)i=2nS(ni)=i=1n[n=1]i=2nS(ni)=1i=2nS(ni)

至此,便可用数论分块求得。

Link
il int get_mu(int x) {
    if (x <= 10000000) return mu[x];
    if (res2[x]) return res2[x];
    int res = 1;
    for (ll l = 2,r; l <= x; l = r + 1 ) {
        r = x / (x / l);
        res -= (r - l + 1) * get_mu(x / l);
    }
    return res2[x] = res;
}

欧拉函数

欧拉函数,即 φ(n)

同样,令 g(n)=1

S(n)=i=1nd|iφ(d)i=2nS(ni)=i=1nii=2nS(ni)=(n+1)n2i=2nS(ni)

至此,我们也能够使用数论分块解决。

Link
il ll get_phi(ll x) {
    if (x <= 10000000) return phi[x];
    if (res1[x]) return res1[x];
    ll res = 1ll * (1ll + x) * x / 2ll;
    for (ll l = 2,r; l <= x; l = r + 1 ) {
        r = x / (x / l);
        res -= 1ll * (r - l + 1ll) * get_phi(x / l);
    }
    return res1[x] = res;
}

时间复杂度

不会证明。

因为使用的数论分块递归,时间复杂度是 O(n34)
但是如果我们提前预处理出前 n23 的函数的值,则可以在 O(n23) 的时间复杂度内解决。

posted @   songszh  阅读(51)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示