Luogu 3911 最小公倍数之和

感觉自己被早上的名校协作体和下午的数学题虐哭了,每天为自己的菜发愁……

发现$a_{i}$很小,开一个桶记一下每个数 出现的个数,设$c_{i} = \sum_{j = 1}^{n}(a_{j} == i)$。

我们知道$lcm(i, j) == \frac{ij}{gcd(i, j)}$。

记$m = max(a_{i})$。

那么  $\sum_{i = 1}^{n}\sum_{j = 1}^{n}lcm(a_{i}, a_{j}) \  = \sum_{i = 1}^{m}\sum_{j = 1}^{m}\frac{ij}{gcd(i, j)} * c_{i} * c_{j}$。

反演一下,得到  $\sum_{d = 1}^{m}d\sum_{t = 1}^{\left \lfloor \frac{m}{d} \right \rfloor}t^{2} * \mu (t)\sum_{u = 1}^{\left \lfloor \frac{m}{dt} \right \rfloor}\sum_{v = 1}^{\left \lfloor \frac{m}{dt} \right \rfloor}u * v * c_{dtu} * c_{dtv}$。

枚举$T = dt$,得到   $\sum_{T = 1}^{m}(T (\sum_{d | T}d * \mu (d)))(\sum_{u = 1}^{\left \lfloor \frac{m}{T} \right \rfloor}u * c_{Tu})(\sum_{v = 1}^{\left \lfloor \frac{m}{T} \right \rfloor}v * c_{Tv})$。

设$h(T) = \sum_{d | T}d * \mu (d)$,$g(T) = \sum_{d = 1}^{\left \lfloor \frac{m}{T} \right \rfloor}d * c_{Td}$,那么最后的答案就变成了$\sum_{T = 1}^{m}T * h(i) * g^{2}(i)$。

发现$h(i)$是一个积性函数,有$h(1) = 1, h(p) = 1 - p, h(p^{k}) = h(p)$,可以线性筛。

而$g(i)$只要暴力算就可以了。

时间复杂度$O(nlogn)$。

Code:

#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;

const int N = 5e4 + 5;

int n, m = 0, pCnt = 0, pri[N], low[N];
ll h[N], g[N], c[N];
bool np[N];

template <typename T>
inline void read(T &X) {
    X = 0; char ch = 0; T op = 1;
    for(; ch > '9'|| ch < '0'; ch = getchar())
        if(ch == '-') op = -1;
    for(; ch >= '0' && ch <= '9'; ch = getchar())
        X = (X << 3) + (X << 1) + ch - 48;
    X *= op;
}

inline void chkMax(int &x, int y) {
    if(y > x) x = y;
}

inline void sieve() {
    h[1] = 1;
    for(int i = 2; i <= m; i++) {
        if(!np[i]) {
            pri[++pCnt] = i;
            low[i] = i;
            h[i] = (ll)1 - i;
        }
        for(int j = 1; j <= pCnt && i * pri[j] <= m; j++) {
            np[i * pri[j]] = 1;
            if(i % pri[j] == 0) {
                low[i * pri[j]] = low[i] * pri[j];
                if(low[i] == i) h[i * pri[j]] = h[i];
                else h[i * pri[j]] = h[i / low[i]] * h[pri[j] * low[i]];
                break;
            }
            low[i * pri[j]] = pri[j];
            h[i * pri[j]] = h[i] * h[pri[j]];
        }
    }
    
/*    for(int i = 1; i <= m; i++)
        printf("%lld ", h[i]);
    printf("\n");   */
}

int main() {
    read(n);
    for(int i = 1; i <= n; i++) {
        ll x; read(x);
        c[x]++;
        chkMax(m, x);
    }    
    
/*    for(int i = 1; i <= m; i++)
        printf("%lld ", c[i]);
    printf("\n");   */
    
    sieve();
    for(int i = 1; i <= m; i++)
        for(int j = 1; j <= m / i; j++)
            g[i] += c[i * j] * j;
    
/*    for(int i = 1; i <= m; i++)
        printf("%lld ", g[i]);
    printf("\n");   */
    
    ll ans = 0LL;
    for(int i = 1; i <= m; i++)
        ans += i * h[i] * g[i] * g[i];
    
    printf("%lld\n", ans);
    return 0;
}
View Code

 

   

posted @ 2018-09-03 16:27  CzxingcHen  阅读(180)  评论(0编辑  收藏  举报