码迷,mamicode.com
首页 > 其他好文 > 详细

[模板][P3377]杜教筛

时间:2019-02-18 14:44:28      阅读:159      评论:0      收藏:0      [点我收藏+]

标签:快速   线性   signed   ret   get   数据   print   phi   break   

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} \rfloor} f(d) g(k)?\)

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

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

\(=\sum_{k=1}^{x}g(d)F(\lfloor \frac{x}{k} \rfloor)\)

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

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

只要能快速求出 \(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} \rfloor)\)

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

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

递归求解即可

#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\n",get_ph(n),get_mu(n));
    }
    return 0;
}

[模板][P3377]杜教筛

标签:快速   线性   signed   ret   get   数据   print   phi   break   

原文地址:https://www.cnblogs.com/list1/p/10395182.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!