bzoj 3944 Sum 杜教筛

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


传送门
天天做裸题我没救了……
第一问见bzoj4805
不过这题里 ϕ 的前缀和我记为了S,待会儿看代码可能要注意。
莫比乌斯函数刚看不久,性质还记得几个,
那么这个就有用了:
d|iμ(d)=x
i=1x=1i>1x=0
那么同样的套路,令 M(n)=ni=1μ(i)
那么推导如下:

i=1nd|iμ(d)=1=k=1ni=1n/kμ(i)//=k=1nM(n/k)k=1nM(n/k)=M(n)+k=2nM(n/k)=1M(n)=1k=2nM(n/k)

然后记忆化搜索即可,O( n23 )。
由于n很大,所以要用map或者哈希的方法来存。
map强行多一个log。。于是我就光荣被卡。。
后面看到一些题解用map过了,只是增大了预处理的量,
想想觉得线性筛真的不烂,所以调到了250W,竟然11s-卡过了= =
汗。。

注意一下n=2^31-1的时候开long long的问题。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int 
    maxn=2500000;
ll S[maxn],M[maxn];
int mu[maxn],phi[maxn],prime[maxn];
bool notprime[maxn];
map<int,ll>f;
void Pre(){
    notprime[1]=1,mu[1]=1,phi[1]=1;
    int pcnt=0;
    S[1]=1,M[1]=1;
    for (int i=2;i<maxn;i++){
        if (!notprime[i]){
            mu[i]=-1,phi[i]=i-1;
            prime[++pcnt]=i;
        }
        for (int j=1;j<=pcnt;j++){
            if (prime[j]*i>=maxn) break;
            notprime[prime[j]*i]=1;
            if (i%prime[j]){
                mu[i*prime[j]]=-mu[i];
                phi[i*prime[j]]=phi[i]*(prime[j]-1);
            } else{
                mu[i*prime[j]]=0;
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
        }
        S[i]=S[i-1]+(ll)phi[i],M[i]=M[i-1]+(ll)mu[i];
    }
}
ll solve_phi(int n){
    if (n<maxn) return S[n];
    if (f[n]) return f[n];
    ll ans=(ll)n*(1LL+n)/2LL,last;
    for (ll i=2;i<=n;i=last+1){
        last=n/(n/i);
        ans-=solve_phi(n/i)*(last-i+1);
    }
    f[n]=ans;
    return ans;
}
ll solve_mu(int n){
    if (n<maxn) return M[n];
    if (f[n]) return f[n];
    ll ans=1LL,last;
    for (ll i=2;i<=n;i=last+1){
        last=n/(n/i);
        ans-=solve_mu(n/i)*(last-i+1);
    }
    f[n]=ans;
    return ans;
}
int main(){
    Pre();
    int n,cas;scanf("%d",&cas);
    while (cas--){
        scanf("%d",&n);
        f.clear(),printf("%lld ",solve_phi(n));
        f.clear(),printf("%lld\n",solve_mu(n));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ThinFatty/article/details/78479558
今日推荐