AtCoder Beginner Contest 351 F Solution

AT_abc351_f Double Sum

题面简述

对于长度为 \(n\) 的数列 \(a\)

\[\sum_{i=1}^n\sum_{j=i+1}^n \max(a_j-a_i,0) \]

省流

树状数组 + 离散化。

没有 E 难。

思路

首先,尽管内存限制为 1024MiB ,我们仍然不能使用未经离散化的树状数组,因为会空间超限。

按照顺序遍历 \(a\) 中的元素 \(a_k\) ,则题面中 \(j=k\) 时对答案做的贡献就是

\[\sum_{i=1}^{j-1} (a_j-a_i) [a_j>a_i] \]

将其展开得

\[a_j\times\sum_{i=1}^{j-1} [a_j>a_i]-\sum_{i=1}^{j-1} a_i[a_j>a_i] \]

显然可以使用树状数组维护。

时间复杂度为 \(O(n\log n)\)

代码

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 4e5 + 10;
using ll = long long;
int n, m;
ll tr1[N], tr2[N], ret, x[N], y[N], tmp;
void update(ll *tr, int x, int y)
{
    while (x < N)
        tr[x] += y, x += (x & -x);
}
ll query(ll *tr, int x)
{
    ll res = 0;
    while (x)
    {
        res += tr[x];
        x -= (x & -x);
    }
    return res;
}
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        scanf("%lld", x + i);
        y[i] = x[i];
        // ret += x * query(tr2, x) - query(tr1, x);
        // update(tr1, x + 1, x);
    }
    sort(y + 1, y + n + 1);
    m = unique(y + 1, y + n + 1) - y - 1;
    for (int i = 1; i <= n; i++)
    {
        tmp = x[i];
        x[i] = lower_bound(y + 1, y + m + 1, x[i]) - y;
        ret += tmp * query(tr2, x[i]) - query(tr1, x[i]);
        update(tr1, x[i] + 1, tmp);
        update(tr2, x[i] + 1, 1);
    }
    printf("%lld\n", ret);
}
posted @ 2024-04-28 13:18  丝羽绫华  阅读(114)  评论(1编辑  收藏  举报