Dircliet 前缀和

以下若无特殊说明,皆认为 \(a_i\) 已知,\(b_i\) 非已知。

前缀和

设有:

\[
b_n=\sum\limits_{i|n}a_i

\]

显然通过枚举我们可以用 \(O(\sum\left\lfloor \frac{n}{i} \right\rfloor=n\log n)\) 的时间复杂度来做这个事情。我们考虑有没有更为优秀的算法。

根据唯一分解定理,我们有:

\[
n=\prod p_i^{\alpha_i}

\]

那么其实我们可以用 \((\alpha_1,\alpha_2,...)\) 去表示 \(n\)。所以上面的这些东西我们可以看做是一个高维的前缀和。类比做二维前缀和我们可以先通过对第一维做前缀和然后再对第二维做前缀和得到,高维前缀和我们可以通过对每一维做前缀和的得到最终结果。
代码


for(int i=1;i<=tail&&Prime[i]<=n;i++)
    for(int j=1;j*Prime[i]<=n;j++) a[j*Prime[i]]+=a[j];

不难发现复杂度和埃氏筛的复杂度相同,为 \(O(n\log n)\)

Dirchlet 后缀和

我们需要求

\[
b_i=\sum\limits_{i|n}a_n

\]

显然做后缀和只需要把刚刚那个反过来做就可以。


for(int i=1;i<=tail&&Prime[i]<=n;i++)
    for(int j=n/Prime[i];j>=1;j--) a[j]+=a[j*Prime[i]];

倒推 Dirichlet 前缀和

\[
a_n=\sum\limits_{i|n}b_i

\]

这就相当于告诉我们前缀和结果让我们求每一个位置的元素,我们类比二维前缀和做法,不难得出结论。


for(int i=1;i<=tail$$Prime[i]<=n;i++)
    for(int j=n/Prime[i];j>=1;j--) a[j*Prime[i]]-=a[j];

倒推 Dirichlet 前缀和

\[
a_i=\sum\limits_{i|n}b_n

\]


for(int i=1;i<=tail&&Prime[i]<=n;i++)
    for(int j=1;j*Prime[i]<=n;j++) a[j*Prime]+=a[j]

只要把这个东西高维前缀和的本质说清楚了,其余就很好理解。

原文链接: https://www.cnblogs.com/TianMeng-hyl/p/15829088.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    Dircliet 前缀和

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/187079

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月12日 上午11:14
下一篇 2023年2月12日 上午11:14

相关推荐