首页 > 其他 > 详细

[P3911] 最小公倍数之和 - 莫比乌斯反演

时间:2020-06-24 10:15:00      阅读:70      评论:0      收藏:0      [点我收藏+]

Description

对于\(A_1,A_2,\cdots,A_N\),求 \(\sum_{i=1}^N\sum_{j=1}^N lcm(A_i,A_j)\)

Solution

经过一波推导得到

\[\sum_{i=1}^N\sum_{j=1}^N lcm(A_i,A_j) = \sum_{d=1}^N d (\sum_{i=1}^{N/d} i C_{id})^2 \sum_{k|d}k\mu(k) \]

暴力计算即可

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

#define int long long
const int N = 100005;
const int MAXN = 100005;

bool isNotPrime[MAXN + 1];
int mu[MAXN + 1], phi[MAXN + 1], primes[MAXN + 1], cnt;
inline void euler() {
    isNotPrime[0] = isNotPrime[1] = true;
    mu[1] = 1;
    phi[1] = 1;
    for (int i = 2; i <= MAXN; i++) {
        if (!isNotPrime[i]) {
            primes[++cnt] = i;
            mu[i] = -1;
            phi[i] = i - 1;
        }
        for (int j = 1; j <= cnt; j++) {
            int t = i * primes[j];
            if (t > MAXN) break;
            isNotPrime[t] = true;
            if (i % primes[j] == 0) {
                mu[t] = 0;
                phi[t] = phi[i] * primes[j];
                break;
            } else {
                mu[t] = -mu[i];
                phi[t] = phi[i] * (primes[j] - 1);
            }
        }
    }
}

int n,c[N];

signed main() {
    euler();
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++) {
        int tmp;
        cin>>tmp;
        c[tmp]++;
    }
    int ans=0;
    for(int d=1;d<=N;d++) {
        int a1=0,a2=0;
        for(int i=1;i<=N/d;i++) {
            a1+=i*c[i*d];
        }
        vector <int> fac;
        for(int i=1;i*i<=d;i++) {
            if(d%i==0) {
                fac.push_back(i);
                if(i*i!=d) fac.push_back(d/i);
            }
        }
        for(int k:fac) {
            a2+=k*mu[k];
        }
        ans+=d*a1*a1*a2;
    }
    cout<<ans;
}

[P3911] 最小公倍数之和 - 莫比乌斯反演

原文:https://www.cnblogs.com/mollnn/p/13185826.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!