• min_25 筛入门


    前置知识 1:埃氏筛法

    主要被应用于筛出 \(n\) 以内的质数。
    需要对 \(\sqrt{n}\) 以内的质数枚举其倍数,划去 \(n\) 以内的它们的倍数,剩下的数字就是 \(n\) 以内的质数。

    前置知识 2:积性函数

    定义:对于函数 \(f(x)\) ,若有 \(\gcd(x,y)=1\) ,则满足 \(f(x)\times f(y)=f(x\times y)\),这样的函数 \(f(x)\) 被称为积性函数。

    若对于任意的 \(x,y\),均有 \(f(x)\times f(y)=f(x\times y)\),则这样的函数 \(f(x)\) 被称为完全积性函数

    现在考虑埃氏筛法的过程,若我们要求某个积性函数的前缀和,可以假设对每个数字进行质因数分解,然后模拟埃氏筛法的过程,枚举该质因子的指数。这时我们可以保证这个分解出来的 \(p_i^{e_i}\) 与其他部分互质,由积性函数的性质,能直接乘起来计入贡献。

    这个看上去很暴力的想法,就是 min_25 筛法的核心思想。

    min_25 筛

    我们需要计算的是某个积性函数 \(f(n)\) 的前缀和,这个 \(f\) 需要满足在 \(p\) 处的点值是一个关于 \(p\) 的低次多项式,在 \(p^e\) 处的点值可以快速计算。

    以下内容与多数教程有较大差异,如果发现问题还请读者指出

    我们第一部分需要计算是 \(f\) 的质数处点值的前缀和。

    将函数 \(f\) 质数处的点值用若干个函数 \(g_{1\dots k}\) 的和差表示,其中对每一项要求 \(g\)完全积性函数,且可以快速求前缀和。我们第一部分需要计算的只是 \(f\) 的质数处点值,而 \(f\) 的这部分是可以通过 \(g\) 直接得到的,至于合数处的点值,可以不用去管它,因为它们会在容斥的过程中被除掉。

    可以发现,我们构造的完全积性函数实际上全部形如 \(i^k\) ,因此我们可以解决的 \(f(n)=\sum_{k}a_k\times n^k\) ,实际上是对每个 \(k\) 构造 \(i^k\) ,分别求出质数处的点值后再乘上 \(a_k\) ,将贡献计入。

    例如:

    • 求质数个数,将质数处的点值置为 \(1\),再做前缀和,因此构造的函数为全 \(1\) 函数
    • 求质数和,将质数处的点值置为 \(i\),再做前缀和,因此构造的函数为 \(Id\)
    • \(\varphi(i)\) 质数处的点值为 \(i-1\) ,可以构造成 \(Id\)\(1\) 两个函数的差
    • \(\mu(i)\) 质数处的点值为 \(-1\) ,可以构造 \(1\) 函数,结果取相反数
    • \(\frac{1}{\sigma_0(i)}\) 质数处的点值为 \(\frac{1}{2}\) ,可以构造 \(1\) 函数,结果乘 \(\frac{1}{2}\)
    • loj #6053 \(2\) 处点值为 \(3\) ,奇质数处点值为 \(i-1\) ,可以最后单独处理 \(2\) ,其他构造同 \(\varphi\)
    • 洛谷P5325 质数处点值为 \(i^2-i\) ,构造 \(Id2\)\(Id\) ,分别处理然后作差

    下文只对求其中的一个 \(g\) 进行讨论。

    第一部分

    \(G(i,j)\) 表示前 \(i\) 个数字,进行了 \(j\) 轮埃氏筛法,剩余的数字(即为最小的质因数 \(P> p_j\) 的数字和更小的质数)的 \(g\) 函数值之和。

    下面考虑递归计算 \(G(i,j)\),需要分两种情况讨论:

    1. \(p_j^2>i\) ,显然 \(G(i,j)=G(i,j-1)\) ,因为 \(p_j\) 筛不掉任何一个新的数字

    2. \(p_j^2\le i\) ,这一次筛掉了的数字满足这样的性质:不能被 \(p_{1,2\dots j-1}\) 整除,能被 \(p_j\) 整除,可以发现这些数字的函数值之和可以表示为 \(g(p_j)(G(\lfloor\frac{i}{p_j}\rfloor,j-1)-G(p_j-1,j-1))\) ,理解起来就是对 \(\lfloor\frac{i}{p_j}\rfloor\) 以内的最小质因子不小于 \(p_j\) 的数字强行乘一个 \(p_j\) ,构造出以 \(p_j\) 为最小值质因子的所有数字,也就是需要减去的部分。至于减去 \(G(p_j-1,j-1))\) 的目的是除去 \(G(\lfloor\frac{i}{p_j}\rfloor,j-1)\) 里面多出来的前 \(j-1\) 小的质数的点值。

    两种情况合并起来就可以计算 \(G(i,j)\) 了,也就是

    \[ G(i,j)=G(i,j-1)-[p_j^2\le i]\times g(p_j)\times [G(\lfloor\frac{n}{p_j}\rfloor,j-1)-G(p_j-1,j-1)] \]

    第二部分

    有了 \(G\) 函数的值,如何计算 \(f\) 的前缀和呢?

    类似第一部分的方法,设 \(F(n,j)\) 表示前 \(n\) 个数字,进行了 \(j\) 轮埃氏筛法,剩余的数字的 \(f\) 函数之和

    \(F(n,j)\)\(1\),质数,合数三部分计算,\(1\) 直接加上,新加进来的所有质数的点值之和可以用 \(G(n,|p|)-\sum_{i=1}^{j-1}f(p_i)\) 表示(减去的那部分是因为质数大小的限制)。

    对于合数的部分,考虑枚举其一个质因子及其指数,拆分出来计算贡献,因为积性函数的值关于不同质因子独立,所以可以直接乘起来。要注意这里会把 \(p_k^e\) 筛掉,所以要手动补回来。

    表示成式子是这样:

    \[ F(n,j)=G(n,|p|)-\sum_{i=1}^{j-1}f(p_i)+\sum_{k> j}\sum_{e}(f(p_k^e)F(\lfloor\frac{n}{p_k^e}\rfloor,k+1)+f(p_k^{e+1})) \]

    时间复杂度

    第一部分暴力递推,第二部分直接递归,不需要记忆化

    时间复杂度并没有统一的说法,我们只需要知道在 \(1\) 秒的时限内可以跑一次 \(10^{11}\) ,或两三次 \(10^{10}\),或若干次 \(10^9\) 就可以了。

    实现

    通过一些整除分块的知识,可以知道第一部分只有 \(O(\sqrt{n})\) 个点值有用,那么我们预处理出这些位置。这里有一个储存的技巧:因为大于 \(\sqrt{n}\) 的和小于它的都有不超过 \(\sqrt{n}\) 个,因此可以分别开数组储存,不需要开 map 。

    \(G\) 数组只需要开一维,从高往低操作就可以了。

    第二部分直接暴力递归求解,没啥好说的。

  • 相关阅读:
    设计模式JS中的单例模式应用(一)
    SSD5_ Exercise 4分析
    JavaEE学习笔记
    SSD5_Exercise5分析
    SSD5_Optional Exercise6分析
    ACM相关网站
    hdu 2066 一个人的旅行【Dijkstra 12级新生训练—图论E】
    新队员图论基础_【CSUST_12级训练】
    hdu 2112 Today【F map + Floyd 入门训练】
    turtle库笔记
  • 原文地址:https://www.cnblogs.com/ehuohz/p/15101286.html
Copyright © 2020-2023  润新知