BZOJ 3944 - Sum(杜教筛)

题目

戳这里

子问题:

    i=1nφ(i)~~~~\sum_{i=1}^{n}\varphi(i)

因为

    inφ(i)=n~~~~\sum_{i|n}\varphi(i)=n

所以

    φ(n)=nin,i<nφ(i)~~~~\varphi(n)=n-\sum_{i|n,i<n}\varphi(i)

辣么

    i=1nφ(i)~~~~\sum_{i=1}^{n}\varphi(i)

=i=1n(idi,d<iφ(d))=\sum_{i=1}^{n}(i-\sum_{d|i,d<i}\varphi(d))

=n(n+1)2i=2ndi,d<iφ(d)=\frac{n(n+1)}{2}-\sum_{i=2}^{n}\sum_{d|i,d<i}\varphi(d)

=n(n+1)2i=2nd=1niφ(d)=\frac{n(n+1)}{2}-\sum_{i=2}^{n}\sum_{d=1}^{\lfloor\frac{n}{i}\rfloor}\varphi(d)

同理
子问题:

    i=1nμ(i)~~~~\sum_{i=1}^{n}\mu(i)

因为

    inμ(i)=[i==1]~~~~\sum_{i|n}\mu(i)=[i==1]

所以

    φ(n)=[n==1]in,i<nφ(i)~~~~\varphi(n)=[n==1]-\sum_{i|n,i<n}\varphi(i)

辣么

    i=1nμ(i)~~~~\sum_{i=1}^{n}\mu(i)

=i=1n([i==1]di,d<iμ(d))=\sum_{i=1}^{n}([i==1]-\sum_{d|i,d<i}\mu(d))

=1i=2ndi,d<iμ(d)=1-\sum_{i=2}^{n}\sum_{d|i,d<i}\mu(d)

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

两个子问题都可以用杜教筛O(n23)O(n^{\frac{2}{3}})下求解

代码:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<map>
#include<vector>
#include<iostream>
#include<algorithm>
 
#define maxn 5000000
 
using namespace std;
 
inline int getint()
{
    int num=0,flag=1;char c;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
    return num*flag;
}

map<long long,long long>Mu,Phi;
bool not_prime[maxn+5];
long long phi[maxn+5],mu[maxn+5],prime[maxn+5],cnt;
long long n;
 
inline void init()
{
    mu[1]=phi[1]=1;
    for(int i=2;i<=maxn;i++)
    {
        if(!not_prime[i])prime[++cnt]=i,mu[i]=-1,phi[i]=i-1;
        for(int j=1;j<=cnt&&i*prime[j]<=maxn;j++)
        {
            not_prime[i*prime[j]]=1;
            if(i%prime[j])mu[i*prime[j]]=-mu[i],phi[i*prime[j]]=phi[i]*phi[prime[j]];
            else{phi[i*prime[j]]=phi[i]*prime[j];break;}
        }
    }
    for(int i=1;i<=maxn;i++)phi[i]+=phi[i-1],mu[i]+=mu[i-1];
}
 
inline long long solvephi(long long x)
{
    if(x<=maxn)return phi[x];
    if(Phi.count(x))return Phi[x];
    long long Sum=1ll*x*(1ll*x+1)/2;
    for(long long i=2,j;i<=x;i=j+1)
        j=min(x/(x/i),x),Sum-=1ll*(j-i+1)*solvephi(x/i);
    return Phi[x]=Sum;
}
 
inline long long solvemu(long long x)
{
    if(x<=maxn)return mu[x];
    if(Mu.count(x))return Mu[x];
    long long Sum=1;
    for(long long i=2,j;i<=x;i=j+1)
        j=min(x/(x/i),x),Sum-=1ll*(j-i+1)*solvemu(x/i);
    return Mu[x]=Sum;
}
 
int main()
{
    init();
    int T=getint();
    while(T--)
    {
        n=getint();
        printf("%lld %lld\n",solvephi(n),solvemu(n));
    }
}
posted @ 2018-12-10 22:26  Izayoi_Doyo  阅读(128)  评论(0编辑  收藏  举报