洛谷P3964
image
代码:

#include <vector>
#include <algorithm>
using namespace std;

typedef long long LL;

int main() {
    int n;
    cin >> n;
    vector<LL> u(n), v(n);
    for (int i = 0; i < n; i++) {
        LL x, y;
        cin >> x >> y;
        u[i] = x + y;
        v[i] = x - y;
    }

    // 处理u数组:排序并计算前缀和
    vector<LL> sorted_u = u;
    sort(sorted_u.begin(), sorted_u.end());
    vector<LL> prefix_u(n + 1, 0);
    for (int i = 0; i < n; i++) {
        prefix_u[i + 1] = prefix_u[i] + sorted_u[i];
    }

    // 处理v数组:排序并计算前缀和
    vector<LL> sorted_v = v;
    sort(sorted_v.begin(), sorted_v.end());
    vector<LL> prefix_v(n + 1, 0);
    for (int i = 0; i < n; i++) {
        prefix_v[i + 1] = prefix_v[i] + sorted_v[i];
    }

    LL min_total = 1e18;

    // 遍历每个点,计算其对应的sum_u + sum_v
    for (int i = 0; i < n; i++) {
        LL ui = u[i];
        // 计算sum(|u_j - ui|)
        int k = lower_bound(sorted_u.begin(), sorted_u.end(), ui) - sorted_u.begin();
        LL sum_u = ui * k - prefix_u[k] + (prefix_u[n] - prefix_u[k]) - ui * (n - k);

        LL vi = v[i];
        // 计算sum(|v_j - vi|)
        int m = lower_bound(sorted_v.begin(), sorted_v.end(), vi) - sorted_v.begin();
        LL sum_v = vi * m - prefix_v[m] + (prefix_v[n] - prefix_v[m]) - vi * (n - m);

        LL total = sum_u + sum_v;
        if (total < min_total) {
            min_total = total;
        }
    }

    cout << min_total / 2 << endl;
    return 0;
}

由题意八个格子都可以走那么就是切比雪夫距离切比雪夫坐标。我们要求距离和,转化成曼哈顿距离比较好求。
image
从图片可以知道,代码将切比雪夫距离转化成曼哈顿距离,只是除2操作在最后进行。
然后因为曼哈顿距离的特性,x坐标和y坐标可以分开计算,然后因为是排序后的坐标又因为下面:
image
所以可以通过前缀和快速求的。