洛谷P4213(杜教筛)

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

const int maxn = 3e6 + 3;
int t, n, cnt;
bool v[maxn];
short mu[maxn];
int isp[maxn], phi[maxn];
LL sum1[maxn];
int sum2[maxn];
unordered_map<int,LL> dp1;
unordered_map<int,int> dp2;

void init() {
    mu[1] = phi[1] = 1;
    for(int i = 2; i < maxn; ++i) {
        if(!v[i]) {
            v[i] = 1;
            mu[i] = -1;
            phi[i] = i - 1;
            isp[cnt++] = i;
        }
        for(int j = 0; j < cnt && i * isp[j] < maxn; ++j) {
            v[i*isp[j]] = 1;
            mu[i*isp[j]] = -mu[i];
            if(i % isp[j] == 0) {
                mu[i*isp[j]] = 0;
                phi[i*isp[j]] = phi[i] * isp[j];
                break;
            }
            phi[i*isp[j]] = phi[i] * (isp[j] - 1);
        }
    }
    for(int i = 1; i < maxn; ++i) sum1[i] = sum1[i-1] + phi[i], sum2[i] = sum2[i-1] + mu[i];
}

LL getnum1(int x) {
    if(x < maxn) return sum1[x];
    if(dp1[x]) return dp1[x];
    LL ans = 1LL * x * (x + 1) / 2;
    for(int l = 2, r; l <= x; l = r + 1) {
        r = x / (x / l);
        ans = ans - 1LL * (r - l + 1) * getnum1(x/l);
    }
    return dp1[x] = ans;
}

LL getnum2(int x) {
    if(x < maxn) return sum2[x];
    if(dp2[x]) return dp2[x];
    LL ans = 1;
    for(int l = 2, r; l <= x; l = r + 1) {
        r = x / (x / l);
        ans = ans - 1LL * (r - l + 1) * getnum2(x/l);
    }
    return dp2[x] = ans;
}

int main() {
    init();
    scanf("%d", &t);
    while(t--) {
        scanf("%d", &n);
        printf("%lld %lld
", getnum1(n), getnum2(n));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Dillonh/p/10951006.html