[题解]P6117 [JOI 2019 Final] 硬币收藏 / Coin Collecting

思路

每一个硬币最终都会走到 \(2 \times n\) 的矩形里面,所以不妨将它们先到其到矩形中最近的节点。

现在只需要在这个矩形中调整使每一个位置都有一个硬币。贪心的,我们希望让 \(x\) 更小的填的位置尽量靠前。

从前往后扫,记 \(a,b\) 分别表示 \(y = 1,y = 2\) 的多余的硬币。当 \(a > 0,b < 0\) 时,需要将 \(a\) 分一些给 \(b\);当 \(a < 0,b > 0\) 时,需要将 \(b\) 分一些给 \(a\)。因为我们在此时需要将 \(|a| + |b|\) 个硬币移动到经过该点,加上贡献即可。

Code

#include <bits/stdc++.h>
#define re register
#define fst first
#define snd second
#define int long long

using namespace std;

typedef pair<int,int> pii;
const int N = 1e5 + 10;
const int inf = (int)(1e18) + 10;
int n,ans;
int num[N][5];

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

signed main(){
    n = read();
    for (re int i = 1,x,y;i <= 2 * n;i++){
        x = read(),y = read();
        if (x < 1){ ans += (1 - x); x = 1; }
        else if (x > n){ ans += (x - n); x = n; }
        if (y <= 1){ ans += (1 - y); y = 1; }
        else{ ans += (y - 2); y = 2; }
        num[x][y]++;
    }
    for (re int i = 1,a = 0,b = 0;i <= n;i++){
        a += (num[i][1] - 1),b += (num[i][2] - 1);
        while (a > 0 && b < 0) a--,b++,ans++;
        while (a < 0 && b > 0) a++,b--,ans++;
        ans += (abs(a) + abs(b));
    } printf("%lld",ans);
    return 0;
}
posted @ 2025-11-05 16:34  WBIKPS  阅读(5)  评论(0)    收藏  举报