【Bzoj3944】杜教筛模板(狄利克雷卷积搞杜教筛)

  题目链接

  哇杜教筛超炫的

  有没有见过$O(n^frac{2}{3})$求欧拉函数前缀和的算法?没有吧?蛤蛤蛤

  首先我们来看狄利克雷卷积是什么

  首先我们把定义域是整数,陪域是复数的函数叫做数论函数。

  然后狄利克雷卷积是个函数和函数的运算。

  比如说有两个数论函数f,g

  那么它们的狄利克雷卷积就是f*g,记为h

  然后我们惊奇地发现$h(i)=sumlimits_{d|i}f(d)g(frac{i}{d})$

  而且狄利克雷卷积好像是个群,然后它就能满足交换律结合律分配律balaba

  那么这个玩意有什么卵用呢?

  (显然它很有卵用)

  我们再说一个数论函数叫单位元。

  e(1)=1 e(n)=0(n>1)

  然后我们发现任意函数f(x)有f*e=f

  然后就引出我们的杜教筛,这里计算莫比乌斯函数的前缀和

  设$S(n)=sumlimits_{i=1}^{n}miu(i)$

  然后我们随便代一个数论函数g,套上狄利克雷卷积

  $sumlimits_{i=1}^{n}(g*miu)(i)=sumlimits_{i=1}^{n}sumlimits_{d|i}miu(frac{i}{d})g(d)$

  $=sumlimits_{d=1}^{n}sumlimits_{d|i}miu(frac{i}{d})g(d)$

  $=sumlimits_{d=1}^{n}g(d)sumlimits_{i=1}^{frac{n}{d}}miu(i)$

  $=sumlimits_{d=1}^{n}g(d)S(frac{n}{d})$
  所以说$g(1)S(n)=sumlimits_{i=1}^{n}g(i)S(frac{n}{i})-sumlimits_{i=2}^{n}g(i)S(frac{n}{i})$

       $=sumlimits_{i=1}^{n}(g*miu)(i)-sumlimits_{i=2}^{n}g(i)S(frac{n}{i})$

  然后我们惊奇的发现,如果我们设g(x)=1

  因为1*miu=e(因为有个定理是$sumlimits_{d|n}miu(d)=$  n=1时1,n>1时0)

  那么这玩意就变成了$S(n)=1-sumlimits_{i=2}^{n}S(frac{n}{d})$

  然后这个玩意可以先用线性筛求出$n^frac{2}{3}$的前缀和,然后用这个表达式应用数论分块,递归搞搞就好了

  就问炫不炫

  

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<map>
#define maxn 5000000
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

int prime[maxn],tot;
bool s[maxn];
long long phi[maxn];
long long miu[maxn];
map<int,long long>_phi,_miu;

long long calcmiu(long long n){
    if(n<maxn)    return miu[n];
    if(_miu.count(n)) return _miu[n];
    long long x=2,ans=1;
    while(x<=n){
        long long y=n/(n/x);
        ans-=calcmiu(n/x)*(y-x+1);
        x=y+1;
    }
    return _miu[n]=ans;
}

long long calcphi(long long n){
    if(n<maxn)    return phi[n];
    if(_phi.count(n)) return _phi[n];
    long long x=2,ans=n*(n+1)/2;
    while(x<=n){
        long long y=n/(n/x);
        ans-=calcphi(n/x)*(y-x+1);
        x=y+1;
    }
    return _phi[n]=ans;
}

int main(){
    int T=read();
    s[1]=1;miu[1]=1;phi[1]=1;miu[0]=0;phi[0]=0;
    for(int i=2;i<maxn;++i){
        if(!s[i]){
            s[i]=1;
            phi[i]=i-1;
            miu[i]=-1;
            prime[++tot]=i;
        }
        for(int j=1;j<=tot&&prime[j]*i<maxn;++j){
            s[prime[j]*i]=1;
            if(i%prime[j]){
                miu[i*prime[j]]=-miu[i];
                phi[i*prime[j]]=phi[i]*(prime[j]-1);
            }
            else{
                phi[i*prime[j]]=phi[i]*prime[j];
                miu[i*prime[j]]=0;
                break;
            }
        }
    }
    for(int i=2;i<maxn;++i){
        phi[i]+=phi[i-1];
        miu[i]+=miu[i-1];
    }
    while(T--){
        long long n=read();
        printf("%lld %lld
",calcphi(n),calcmiu(n));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/cellular-automaton/p/8227802.html