杜教筛&Min_25筛学习笔记

杜教筛

这个东西已经咕了差不多半年QAQ
然后现在才开始写.

有的时候,我们需要完成这样一个问题.
\(\sum_{i=1}^nf(i)\).其中\(f\)是积性函数.
\(n\leq 10^7\)时,可以用线性筛解决这个问题.
然而,起源于\(Project Eular\)的这个黑科技可以把\(n\)的范围扩展到\(10^{11}\)左右.

考虑狄利克雷卷积.
假设\(f*g=h\),那么写成狄利克雷卷积的形式,就是

\[\sum_{i=1}^nh(i)=\sum_{i=1}^n\sum_{d|i}f(i)g(\frac{i}{d})\\ =\sum_{d=1}^ng(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}f(i)\\ =\sum_{d=1}^ng(d)S(\lfloor\frac{n}{d}\rfloor)\\ 把第一项拉出来,得\\ g(1)S(n)=\sum\limits_{i=1}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor)-\sum\limits_{i=2}^{n}g(i)S(\lfloor\frac{n}{i} \rfloor) \]

考虑到\(\lfloor\frac{n}{d}\rfloor\)只有\(\sqrt n\)种取值,于是记忆化搜索一波,美滋滋.
因此,只要可以快速求\(h\)的前缀和与\(g\),就可以快速求\(f\)的和.

时间复杂度大约是\(O(n^{\frac{3}{4}})\),可以用积分证.

下面举几个栗子.

莫比乌斯函数

我们知道\(\mu*1=e\),而\(\sum h=1\),因此就很好求啦.
在存储上也有一个小优化,无需\(map\).考虑到求出的每个\(S(x)\),\(x\)都是\(n\)的因数且\(\frac{n}{x}\)不大,因此只需如下代码即可.

LL calc_miu(int x){
    if(x<maxn)return miu[x];
    else if(w2[n/x])return w2[n/x];
    LL ans=1;
    for(int i=2,ed;i<=x;i=ed+1)
    ed=x/(x/i),ans-=(ed-i+1)*calc_miu(x/i);
    return w2[n/x]=ans;
}
欧拉函数

我们知道\(\varphi*1=id\),因此\(\sum h=\frac{n*(n-1)}{2}\),就很好求啦.
代码如下

LL calc_phi(int x){
    if(x<maxn)return phi[x];
    else if(w1[n/x])return w1[n/x];
    LL ans=(LL)x*(LL)(x+1)/2;
    for(int i=2,ed;i<=x;i=ed+1)
    ed=x/(x/i),ans-=(ed-i+1)*calc_phi(x/i);
    return w1[n/x]=ans;
}

Min_25筛

待UPD

posted @ 2018-12-04 08:52  Romeolong  阅读(610)  评论(0编辑  收藏  举报