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;
}
posted @ 2026-03-31 10:54  SHUddol  阅读(5)  评论(0)    收藏  举报