P4264 [USACO18FEB] Teleportation S 题解

· · 题解

分析

画图

  1. |a|>|a-b|
    • 这时候肯定不会走传送门的,因为运去 x=0 那里都比直接运要远。
  2. |a|<|b|

    • 如图所示,这种情况下三个分段点分别是 2ab2b-2a
  3. a<0<b/b<0<a

    • 如图所示,这种情况下的三个分段点是 0b2b
    • 而且,这三种情况的初始值均为 |a-b|,所以初始值 f(-\infty) 要设成 \sum|a_i-b_i|

实现

代码

#include <bits/stdc++.h>
#define inf 0x7fffffff
#define int long long
using namespace std;
int n, x, y = -inf, s, ans;
map<int, int> mp;

inline void read(int &x) {
    int w = 1;
    char ch = x = 0;
    while (ch < '0' || ch > '9') {
        if (ch == '-') w *= -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9') {
        x = (x << 1) + (x << 3) + ch - 48;
        ch = getchar();
    }
    x *= w;
    return ;
}

signed main() {
    read(n);
    int a, b;
    for (int i = 1; i <= n; i++) {
        read(a), read(b);
        x += abs(a - b);
        if (abs(a) > abs(a-b)) continue; //第一种情况
        mp[b] += 2;
        if ((a < b && a < 0) || (a >= b && a >= 0)) { //处理后两种情况
            mp[0]--;
            mp[b << 1]--;
        } else if ((a < b && a >= 0) || (a >= b && a < 0)) {
            mp[(b - a) << 1]--;
            mp[a << 1]--;
        }
    }
    ans = x;
    int now, tmp;
    for (auto it : mp) { //对于每一个分段点都统计,取最小值
        now = it.first, tmp = it.second;
        x += s * (now - y);
        y = now;
        s += tmp;
        ans = min(ans, x);
    }
    printf("%lld", ans);
    return 0;
}