3944: Sum[杜教筛]

3944: Sum

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 3471  Solved: 946
[Submit][Status][Discuss]

Description

 

Input

一共T+1行
第1行为数据组数T(T<=10)
第2~T+1行每行一个非负整数N,代表一组询问
 

 

 

Output

一共T行,每行两个用空格分隔的数ans1,ans2
 

 

Sample Input

6
1
2
8
13
30
2333

Sample Output

1 1
2 0
22 -2
58 -3
278 -3
1655470 2

HINT

 

Source

 

 

我们考虑令:
\[F_n = \sum_{d|n}\varphi(d)\]

那么,有:
\[\sum_{i=1}^{n}F_i = \sum_{i=1}^{n}\sum_{d|i}\varphi(d) = \sum_{d=1}^{n}\varphi(d)\times \lfloor\frac{n}{d}\rfloor = \sum_{d=1}^{n}\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\varphi(i)\]

为什么最后一步可以这么转化呢?我们考虑一个 \(i\) ,论 \(\varphi(i)\) 对答案的贡献:

在最后一个等式的左边,\(\varphi(i)\) 对答案的贡献为:\(\lfloor\frac{n}{i}\rfloor\),这很显然。

在等式的右边,当 \(i\times d \le n\) 的时候,\(\varphi(i)\)才会对答案产生贡献,所以对于每一个 \(d\le\lfloor\frac{n}{i}\rfloor\)\(\varphi(i)\)都会对答案产生贡献,所以在等式右边,\(\varphi(i)\) 对答案的贡献也为:\(\lfloor\frac{n}{i}\rfloor\)

于是等式是成立的。

不懂的话,移步这里:莫比乌斯反演与杜教筛 笔记

那么就有:
\[\sum_{i=1}^{n}\varphi(i) = \sum_{i=1}^{n}\sum_{d|i}\varphi(d) - \sum_{d=2}^{n}\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\varphi(i)\]

还有:
\[\sum_{i=1}^{n}\sum_{d|i}\varphi(d) = \sum_{i=1}^{n}i = \frac{n\times(n+1)}{2}\]

所以:
\[\sum_{i=1}^{n}\varphi(i) = \frac{n\times(n+1)}{2} - \sum_{d=2}^{n}\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\varphi(i)\]

所以算\(\sum_{i=1}^{n}\varphi(i)\)的时候就可以记忆化搜索啦。

据说,我们把 \(N^{\frac{2}{3}}\) 之内的答案先筛出来,然后再进行记忆化搜索,复杂度就是 \(O(N^{\frac{2}{3}})\)的了。

然后同理,有:
\[\sum_{i=1}^{n}\mu(i) = 1 - \sum_{d=2}^{n}\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\mu(i)\]

时空复杂度均为 \(O(N^{\frac{2}{3}})\)

#include<cstdio>
#include<cstring>
#define clr(s) memset(s,0,sizeof s)
using namespace std;
typedef long long ll;
const int N=1e5+5,M=2e6+5;
int T,n,m,tot,prime[M/3];bool check[M];
ll phi[M],mu[M];
ll alpha[N],beta[N];bool vis[N];
inline void sieve(){
    m=M-5;mu[1]=phi[1]=1;
    for(int i=2;i<=m;i++){
        if(!check[i]) prime[++tot]=i,mu[i]=-1,phi[i]=i-1;
        for(int j=1;j<=tot&&i*prime[j]<=m;j++){
            check[i*prime[j]]=1;
            if(!(i%prime[j])){mu[i*prime[j]]=0;phi[i*prime[j]]=phi[i]*prime[j];break;}
            mu[i*prime[j]]=-mu[i];phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
    }
    for(int i=1;i<=m;i++) mu[i]+=mu[i-1],phi[i]+=phi[i-1];
}
inline ll GetPhi(int x){
    return x<=m?phi[x]:alpha[n/x];
}
inline ll GetMu(int x){
    return x<=m?mu[x]:beta[n/x];
}
void solve(int x){
    if(x<=m) return ;
    int t=n/x;
    if(vis[t]) return ;
    vis[t]=1;
    alpha[t]=(ll)x*((ll)x+1)>>1;
    beta[t]=1;
    for(ll i=2,pos;i<=x;i=pos+1){//假如 x=2^31-1,那么i会爆int 
        pos=x/(x/i);
        solve(x/i);
        alpha[t]-=GetPhi(x/i)*(pos-i+1);
        beta[t]-=GetMu(x/i)*(pos-i+1);
    }
}
int main(){
    sieve();
    for(scanf("%d",&T);T--;clr(vis)){
        scanf("%d",&n);
        if(n<=m){
            printf("%lld %lld\n",phi[n],mu[n]);
        }
        else{
            solve(n);
            printf("%lld %lld\n",alpha[1],beta[1]);
        }
    }
    return 0;
}

 

posted @ 2017-05-14 23:02  神犇(shenben)  阅读(332)  评论(0编辑  收藏  举报