一部分数论题会问一个数论函数的前缀和,不妨令其为 \(S(n)=\sum\limits_{i=1}^n f(i)\) 。有时直接求会比较困难。
杜教筛是通过构建一个函数 \(g\) , \(f*g\) 的前缀和能快速( \(O(1)\) )求出。这样能在低于线性的复杂度内求解 \(S(n)\) 。
具体地来说就是:
\[ \begin{aligned} \sum\limits_{k=1}^{n}\sum\limits_{ij=k}f(i)g(j)=\sum\limits_{ij\leqslant n}f(i)g(j)=\sum\limits_{i=1}^n g(i)S(\lfloor\frac{n}{i}\rfloor) \end{aligned} \]
那么
\[ g(1)S(n)=\sum\limits_{ij\leqslant n}f(i)g(j)-\sum\limits_{i=2}^ng(i)S(\lfloor\frac{n}{i}\rfloor) \]
好像还是没有讲清楚……
举个例子:
比方说 \(f=\mu\) , \(S(n)=\sum\limits_{i=1}^n f(i)\) 。那么可以构造 \(g=id_0\) ,那么有
\[ g(1)S(n)=\sum\limits_{i=1}^n (f*g)(i) - \sum\limits_{i=2}^n g(1)S(\lfloor\frac{n}{i}\rfloor) \]
可以得到
\[ S(n)=1-\sum_{i=2}^n S(\lfloor\frac{n}{i}\rfloor) \]
计算 \(S(n)\) 的时候,需要知道 \(S(i),i\in (2, n)\) 。这个可以进行整除分块。也就是说,假设我们已经知道了 \(S(1\cdots n-1)\) ,那么计算 \(S(n)\) 的复杂度是 \(O(\sqrt{n})\) 的。
将 \(S(n)\) 分为两部分考虑。 当 \(i\geqslant \sqrt{n}\) 时, \(\frac{n}{i}\leqslant n\) 。那么假设把 \(S(1\cdots\sqrt{n})\) 全算了,时间复杂度是 \(O(\sum\limits_{i=1}^{\sqrt{n}} \sqrt{i})\) 的。
再考虑 \(i\leqslant \sqrt{n}\) 的情况。由于 \(\lfloor\frac{\lfloor\frac{n}{i}\rfloor}{j}\rfloor=\lfloor\frac{n}{ij}\rfloor\) ,那么下标大于 \(\sqrt{n}\) 的 \(S\) 在递归过程中 总共 只会被访问到 \(O(\sqrt{n})\) 个。那么求出这 \(O(\sqrt{n})\) 个的时间复杂度是 \(O(\sum\limits_{i=1}^{\sqrt{n}} \sqrt{\frac{n}{i}})\) 。
后一部分的复杂度显然大于前一部分。所以总的时间复杂度是
\[ O(\sum\limits_{i=1}^{\sqrt{n}} \sqrt{\frac{n}{i}})\approx O(\int_{0}^{\sqrt{n}}\sqrt{\frac{n}{x}}dx)=O(n^{\frac{3}{4}}) \]
而实际上可以做得更好。前面计算第一部分的时候,假设了计算了所有的 \(S(1\cdots\sqrt{n})\) 。但最后计算的时候,仍然是舍去的。不妨考虑稍微多预处理一点,来换取总的较小的复杂度。
根据前人经验,用线性筛预处理前 \(n^{\frac{2}{3}}\) 项。那么预处理的时间复杂度是 \(O(n^{\frac{2}{3}})\) 。然后后面一部分的复杂度就变为了
\[ O(\sum\limits_{i=1}^{n^{\frac{1}{3}}} \frac{n}{i})\approx O(\int_{i=0}^{n^{\frac{1}{3}}} \sqrt{\frac{n}{x}} dx) = O(n^{\frac{2}{3}}) \]
由于上面提到的, \(\lfloor\frac{\lfloor\frac{n}{i}\rfloor}{j}\rfloor=\lfloor\frac{n}{ij}\rfloor\) ,需要求出的 \(S\) 的下标都是 \(n\) 的约数。所以可以将下标大于 \(\sqrt{n}\) 的 \(S\) 存在另一个数组的 \(\frac{n}{i}\) 里。这样就省去了 hash 或者 map 。
原文:https://www.cnblogs.com/chy-2003/p/11832146.html