杜教筛

快速求一个积性函数 \(f\) 的前缀和,

记为 \(S\)

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

考虑一个积性函数 \(g\)

\[\begin{aligned} & \sum_{i=1}^{n}(f*g)(i) \\ =& \sum_{i=1}^{n}\sum_{d|n}^{i}f(d)g(\frac{i}{n}) \\ =& \sum_{d=1}^ng(d)\sum_{i=1}^{\frac{n}{d}}f(i) \\ =& \sum_{d=1}^{n}g(d)S(\frac{n}{d}) \\ =& \sum_{d=2}^ng(d)S(\frac{n}{d})+g(1)\times S(n) \end{aligned} \]

所以我们得到了最重要的式子:

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

所以我们只要构造出一个 \(g\) ,我们能快速求出它的前缀和以及 \(f * g\) 的前缀和,那么对后面的整数分块, 复杂度 \(O(n^{\frac{3}{4}})\) , 如果预处理到 \(5e6\), 复杂度近似为 \(O(n^{\frac{2}{3}})\)

伪代码:

ll GetSum(int n) { // 算 f 前缀和的函数
  记忆化
  ll ans = sum( (f * g)(n) ); // 算 f * g 的前缀和
  // 以下这个 for 循环是数论分块
  for(ll l = 2, r; l <= n; l = r + 1) { // 注意从 2 开始
    r = (n / (n / l)); 
    ans -= (g_sum(r) - g_sum(l - 1)) * GetSum(n / l);  // g_sum 是 g 的前缀和 //递归 GetSum 求解
  } return Sum(n) = ans;//记忆化 
}

常用公式:

\[\mu\ *\ 1 = \epsilon \]

\[\varphi\ *\ 1=Id \]

一个小小的拓展:

\(\sum_{i=1}^n\varphi(i) \times i\)

首先来了解一个结论:

\[(\varphi \times Id)\ *\ Id=n^2 \]

(手推一下)

这题就是求 \(f=\varphi\times Id\) 的前缀和,

\(g=Id\)

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

\[(f*g)(n)=n^2 \]

\((f*g)(n)\) 的前缀和为 \(\frac{n(n+1)(2n+1)}{6}\).

然后就可以筛了。

posted @ 2019-02-21 22:31  茶Tea  阅读(129)  评论(0编辑  收藏  举报