zoukankan      html  css  js  c++  java
  • bzoj 3944 杜教筛

    题目中要求phi和miu的前缀和,利用杜教筛可以推出公式。我们令

    那么有公式

    类比欧拉函数,我们可以推出莫比乌斯函数的和公式为  (公式证明懒得写了,主要核心是利用Dirichlet卷积的性质 phi * 1 =id, mu * 1 =0(n>1) 然后利用神奇的杜教筛搞一搞 )

    因为有一个n=1的特例,所以这里有一个1,我一开始错在这里,总和答案差1........

    所以我们可以预处理一波phi和mu的前缀和 然后递归的处理,用map记忆一下就可以了,复杂度为n的三分之二次幂(我不会证明)——by VANE

    #include<bits/stdc++.h>
    using namespace std;
    const int M=5e6;
    bool not_prim[M+1];
    typedef long long ll;
    int prim[M>>1],prim_tot;
    ll mu[M+1],phi[M+1];
    map<int,ll> _phi,_mu;
    void pre()
    {
        mu[1]=1;not_prim[1]=1;
        phi[1]=1;
        for(int i=2;i<=M;++i)
        {
            if(!not_prim[i])
            {
                prim[++prim_tot]=i;
                phi[i]=i-1;
                mu[i]=-1;
            }
            for(int j=1;j<=prim_tot&&prim[j]<=M/i;++j)
            {
                not_prim[prim[j]*i]=1;
                if(i%prim[j]==0)
                {
                    phi[prim[j]*i]=phi[i]*prim[j];
                    mu[prim[j]*i]=0;
                    break;
                }
                phi[prim[j]*i]=phi[i]*phi[prim[j]];
                mu[prim[j]*i]=-mu[i];
            }
        }
        for(int i=1;i<=M;++i)
        {
            phi[i]+=phi[i-1];
            mu[i]+=mu[i-1];
        }
    }
    ll calcphi(ll n)
    {
        if(n<=M) return phi[n];
        map<int,ll>::iterator it;
        if((it=_phi.find(n))!=_phi.end())
        return _phi[n];
        ll i,last;ll res=1ll*n*(n+1)/2;
        for(i=2;i<=n;i=last+1)
        {
            last=n/(n/i);
            res-=(last-i+1)*calcphi(n/i);
        }
        return _phi[n]=res;
    }
    ll calcmu(ll n)
    {
        if(n<=M) return mu[n];
        map<int,ll>::iterator it;
        if((it=_mu.find(n))!=_mu.end()) return _mu[n];
        ll i,last;ll res=1;
        for(i=2;i<=n;i=last+1)
        {
            last=n/(n/i);
            res-=(last-i+1)*calcmu(n/i);
         } 
         return _mu[n]=res;
    }
    int main()
    {
        pre();
        int t;
        scanf("%d",&t);
        while(t--)
        {
            ll n;
            scanf("%lld",&n);
            printf("%lld %lld
    ",calcphi(n),calcmu(n));
        } 
    }
  • 相关阅读:
    如何把自己的百度网盘的内容分享给别人
    postman 中post方式提交数据
    在ThinkPHP中,if标签和比较标签对于变量的比较。
    Linux SVN搭建模式 规格严格
    Redmine安装201209 规格严格
    GBK 规格严格
    MySQL分区优化 规格严格
    Null 规格严格
    Compiler 规格严格
    UDP VS TCP 规格严格
  • 原文地址:https://www.cnblogs.com/nbwzyzngyl/p/8059799.html
Copyright © 2011-2022 走看看