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);
}