杜教筛

2024-08-13

求解积性函数的前缀和,如欧拉函数和莫比乌斯函数

#include <bits/stdc++.h>
#define io cin.tie(0), cout.tie(0), ios::sync_with_stdio(false)
#define LL long long
#define ULL unsigned long long
#define EPS 1e-8
#define INF 0x7fffffff
#define SUB -INF - 1
using namespace std;
const int N = 5000007;
int prime[N];
bool vis[N];
int mu[N];
LL phi[N];
unordered_map<int, int> summu;
unordered_map<int, LL> sumphi;
void init()
{
    int cnt = 0;
    vis[0] = vis[1] = 1;
    mu[1] = phi[1] = 1;
    for (int i = 2; i < N; i++)
    {
        if (!vis[i])
        {
            prime[cnt++] = i;
            mu[i] = -1;
            phi[i] = i - 1;
        }
        for (int j = 0; j < cnt && i * prime[j] < N; j++)
        {
            vis[i * prime[j]] = true;
            if (i % prime[j])
            {
                mu[i * prime[j]] = -mu[i];
                phi[i * prime[j]] = phi[i] * phi[prime[j]];
            }
            else
            {
                mu[i * prime[j]] = 0;
                phi[i * prime[j]] = phi[i] * prime[j];
                break;
            }
        }
    }
    for (int i = 1; i < N; i++)
    {
        mu[i] += mu[i - 1];
        phi[i] += phi[i - 1];
    }
}
LL getsmu(int x)
{
    if (x < N)
        return mu[x];
    if (summu[x])
        return summu[x];
    LL ans = 1;
    for (LL l = 2, r; l <= x; l = r + 1)
    {
        r = x / (x / l);
        ans -= 1ll * (r - l + 1) * getsmu(x / l);
    }
    return summu[x] = ans * 1ll;
}
LL getsphi(int x)
{
    if (x < N)
        return phi[x];
    if (sumphi[x])
        return sumphi[x];
    LL ans = x * ((LL)x + 1) / 2;
    for (LL l = 2, r; l <= x; l = r + 1)
    {
        r = x / (x / l);
        ans -= 1ll * (r - l + 1) * getsphi(x / l);
    }
    return sumphi[x] = ans * 1ll;
}
int main()
{
    init();
    int t;
    scanf("%d", &t);
    while (t--)
    {
        int n;
        scanf("%d", &n);
        printf("%lld %lld\n", getsphi(n), getsmu(n));
    }
    return 0;
}