• [模板][P3377]杜教筛


    Description:

    求 $ sum_{i=1}^n phi(i) ,sum_{i=1}^n mu(i)$

    Hint:

    (n<=10^{10}​)

    Solution:

    考虑积性函数 (f,g,h​) 及其前缀和 (F,G,H​)

    其中 (h=f*g​)

    首先 (H(x)=sum_{n=1}^xh(n))

    (=sum_{n=1}^x sum_{d|n} f(d) g(frac{n}{d}))

    枚举倍数转枚举因数

    (=sum_{k=1}^x sum_{d=1}^{lfloor frac{x}{k} floor} f(d) g(k)​)

    $=sum_{k=1}^x g(k)sum_{d=1}^{lfloor frac{x}{k} floor} f(d) $

    (=sum_{k=1}^x g(k) F(lfloor frac{x}{k} floor))

    (=sum_{k=1}^{x}g(k)F(lfloor frac{x}{k} floor))

    (g(1)F(n)=H(n)-sum_{d=2}^{n}g(d)F(lfloor frac{n}{d} floor))

    此式是杜教筛的核心式,适用于非线性求一个积性函数的前缀和

    只要能快速求出 (H(n),sum g(d)) 就能在$ O(n^{ frac{2}{3}} ) $ 求出(F(n))

    (sum_{i=1}^n phi(i)=frac{n(n+1)}{2}-sum_{i=2}^n phi(lfloor frac{n}{i} floor))

    (sum_{i=1}^n mu(i)=1-sum_{i=2}^n mu(lfloor frac{n}{i} floor))

    先筛出线性数据范围内的,再杜教筛

    递归求解即可

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int mxn=5e6+5,inf=2147483647;
    int T,n,tot;
    int p[mxn],vis[mxn];
    ll mu[mxn],ph[mxn];
    map<int ,ll > smu,sph;
    
    void init()
    {
        vis[1]=mu[1]=ph[1]=1;
        for(int i=2;i<=mxn;++i) {
            if(!vis[i]) mu[i]=-1,ph[i]=i-1,p[++tot]=i;
            for(int j=1;j<=tot&&p[j]*i<=mxn;++j) {
                vis[p[j]*i]=1;
                if(i%p[j]) mu[p[j]*i]=-mu[i],ph[p[j]*i]=ph[p[j]]*ph[i];
                else {ph[p[j]*i]=ph[i]*p[j];break;}
            }
        }
        for(int i=2;i<=mxn;++i) mu[i]+=mu[i-1],ph[i]+=ph[i-1];
    }
    
    ll get_mu(int n)
    {
        if(n<=mxn) return mu[n];
        if(smu[n]) return smu[n]; ll ans=0;
        for(int l=2,r;r<inf&&l<=n;l=r+1) 
            r=n/(n/l),ans+=(r-l+1)*get_mu(n/l);
        return smu[n]=1ll-ans;	
    }
    
    ll get_ph(int n)
    {
        if(n<=mxn) return ph[n];
        if(sph[n]) return sph[n]; ll ans=0;
        for(int l=2,r;r<inf&&l<=n;l=r+1)  //一定是从2开始
            r=n/(n/l),ans+=(r-l+1)*get_ph(n/l);
        return sph[n]=(ull)n*(n+1ll)/2-ans;	
    }
    
    int main()
    {
        cin>>T; init();
        while(T--) {
            scanf("%d",&n);
            printf("%lld %lld
    ",get_ph(n),get_mu(n));
        }
        return 0;
    }
    
  • 相关阅读:
    jdk1.8 LongAdder源码学习
    linux 下 vi 文本编辑如何复制一行粘贴删除一行数据
    远程调试
    本机与远程主机指定端口的网络是否连通
    自定义弹窗
    Windows查看占用端口的进程及其对应的应用程序并关闭之
    超实惠:99元阿里云服务器1核2G内存40G硬盘(SSD)
    Java显式锁学习总结之六:Condition源码分析
    Maven使用国内镜像
    深入理解读写锁—ReadWriteLock源码分析
  • 原文地址:https://www.cnblogs.com/list1/p/10395182.html
Copyright © 2020-2023  润新知