USACO04OPEN MooFest G 加强版 题解
题目重述
给定长度为 \(N\) 的数对序列 \((v_1,x_1),(v_2,x_2),\dots,(v_N,x_N)\),求
\[\sum_{i=2}^{N}\sum_{j=1}^{i-1}\max(v_i,v_j) \lvert x_i-x_j \rvert
\]
解法
首先对数对按照 \(v_i\) 升序规则排序,若两元素 \(v_i\) 相等,则按照 \(x_i\) 升序规则内部排序。
然后对原式进行如下变形:
\[\begin{align}
&\sum_{i=2}^{N}\sum_{j=1}^{i-1}\max(v_i,v_j) \lvert x_i-x_j \rvert \\
=&\sum_{i=2}^{N}\sum_{j=1}^{i-1} v_i\lvert x_i-x_j \rvert \\
=&\sum_{i=2}^{N} v_i\sum_{j=1}^{i-1}\lvert x_i-x_j \rvert \\
=&\sum_{i=2}^{N} v_i\sum_{j=1}^{i-1} [x_i>x_j](x_i-x_j)+[x_i \le x_j](x_j-x_i) \\
=&\sum_{i=2}^{N} v_i\sum_{j=1}^{i-1} [x_i>x_j] x_i-[x_i \le x_j]x_i + [x_i \le x_j] x_j - [x_i>x_j]x_j \\
=& \sum_{i=2}^{N} v_ix_i \left( \sum_{j=1}^{i-1} [x_i>x_j] - \sum_{j=1}^{i-1}
[x_i \le x_j] \right) +
\sum_{i=2}^{N} v_i \left( \sum_{j=1}^{i-1} [x_i \le x_j] x_j - \sum_{j=1}^{i-1} [x_i>x_j]x_j\right) \\
\end{align}
\]
两个括号中的求和可以通过维护两个树状数组计算得出
#include <iostream>
#include <algorithm>
#include <utility>
typedef long long ll;
using namespace std;
const int MAX = 5e4;
ll c[MAX + 10], s[MAX + 10], ans; //树状数组的大小是x的值域
pair<ll, ll> vx[MAX + 10];
int n;
inline int lowbit(int x) {
return x & -x;
}
inline ll sum(ll t[], int x) {
ll s = 0;
while (x > 0)
s += t[x], x -= lowbit(x);
return s;
}
inline void add(ll t[], int x, ll val) {
while (x <= MAX)
t[x] += val, x += lowbit(x);
}
int main() {
cin >> n;
for (int i = 1; i <= n; ++i)
cin >> vx[i].first >> vx[i].second;
sort(vx + 1, vx + n + 1);
add(c, vx[1].second, 1);
add(s, vx[1].second, vx[1].second);
for (int i = 2; i <= n; ++i) {
ans += vx[i].first * vx[i].second *
(2 * sum(c, vx[i].second) - sum(c, MAX));
ans += vx[i].first *
(sum(s, MAX) - 2 * sum(s, vx[i].second));
add(c, vx[i].second, 1);
add(s, vx[i].second, vx[i].second);
}
cout << ans;
return 0;
}

浙公网安备 33010602011771号