luogu3911 最小公倍数之和(莫比乌斯反演)

link

给定\(A_1,A_2,\dots,A_N\),求\(\sum_{i=1}^N\sum_{j=1}^Nlcm(A_i,A_j)\)

\(1\le N\le 50000;1\le A_i\le 50000\)

为了推式子方便我们设:

\(n=50000\) \(a_i=\sum_{j=1}^N[A_j=i]\)

答案就是\(\sum_{i=1}^n\sum_{j=1}^na_ia_jlcm(i,j)\)

\(\sum_{i=1}^n\sum_{j=1}^na_ia_jlcm(i,j)\)

\(=\sum_{i=1}^n\sum_{j=1}^na_ia_j\frac{ij}{\gcd(i,j)}\)

\(=\sum_{p=1}^n\frac1p\sum_{i=1}^n\sum_{j=1}^na_ia_jij[\gcd(i,j)=p]\)

\(=\sum_{p=1}^np\sum_{i=1}^{n/p}\sum_{j=1}^{n/p}a_{ip}a_{jp}ij[\gcd(i,j)=1]\)

\(=\sum_{p=1}^np\sum_{i=1}^{n/p}\sum_{j=1}^{n/p}a_{ip}a_{jp}ij\sum_{d|i,d|j}\mu(d)\)

\(=\sum_{p=1}^np\sum_{d=1}^n\mu(d)d^2\sum_{i=1}^{n/dp}\sum_{j=1}^{n/dp}a_{idp}a_{jdp}ij\)

\(=\sum_{q=1}^nq\sum_{d|q}d\mu(d)\sum_{i=1}^{n/q}\sum_{j=1}^{n/q}a_{iq}a_{jq}ij\)

\(=\sum_{q=1}^nq\sum_{d|q}d\mu(d)\left(\sum_{i=1}^{n/q}a_{iq}i\right)^2\)

\(\sum_{i=1}^{n/q}a_{iq}i\)对于每个\(q\)求值,总复杂度为\(\frac n 1+\frac n 2+\frac n 3+\dots+\frac nn\)复杂度为调和级数\(O(n\log n)\)

前半部分筛\(d\)后枚举\(d\)及其倍数,复杂度还是调和级数\(O(n\log n)\)

然后直接求和就行了,貌似不用打数论分块

41行一遍A。。。真不用打数论分块,复杂度nlogn

#include <cstdio>
using namespace std;

int prime[50010], mu[50010], tot, fuck = 50000;
bool vis[50010];
long long sum1[50010], sum2[50010];
int bucket[50010];

int main()
{
    mu[1] = 1;
    for (int i = 2; i <= fuck; i++)
    {
        if (vis[i] == false) prime[++tot] = i, mu[i] = -1;
        for (int j = 1; j <= tot && i * prime[j] <= fuck; j++)
        {
            vis[i * prime[j]] = true;
            if (i % prime[j] == 0) break;
            mu[i * prime[j]] = -mu[i];
        }
        mu[i] *= i;
    }
    for (int d = 1; d <= fuck; d++)
        for (int q = d; q <= fuck; q += d)
            sum1[q] += mu[d];
    for (int i = 1; i <= fuck; i++)
        sum1[i] *= i;
    int n; scanf("%d", &n);
    for (int x, i = 1; i <= n; i++)
        scanf("%d", &x), bucket[x]++;
    long long ans = 0;
    for (int q = 1; q <= fuck; q++)
    {
        int sb = fuck / q;
        for (int i = 1; i <= sb; i++)
            sum2[q] += bucket[i * q] * (long long)i;
        ans += sum2[q] * sum1[q] * sum2[q];
    }
    printf("%lld\n", ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/oier/p/10298560.html
今日推荐