#10073. 卖匹配羊腿 题解

卖匹配羊腿 题解

你的代码主要有一个贪心错误:

不能把所有同侧、同品种的两只腿都立即翻转。

只有当某一侧的剩余腿数量多于另一侧时,才应该优先利用这一侧的同品种腿对。否则可能增加操作次数。

例如:

左腿:A A
右腿:B B

直接把两只左腿改成 B,需要 2 次操作;如果先翻转一只左腿,再处理,反而需要 3 次。

正确做法如下。

  1. 先消除同品种的左右腿匹配,不需要手术。
  2. 统计剩余的左腿数 cntL 和右腿数 cntR
  3. 如果 cntL > cntR,只使用左腿中同品种成对的部分,每一对翻转一只,代价为 1。
  4. 如果 cntR > cntL,对右腿做同样处理。
  5. 剩余的左右腿需要进行品种修改,数量为 min(cntL,cntR);多出来的一侧每只还需要一次翻转,代价为 abs(cntL-cntR)
#include <bits/stdc++.h>
using namespace std;

int main() {
    freopen("pair.in", "r", stdin);
    freopen("pair.out", "w", stdout);

    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, L, R;
    cin >> n >> L >> R;

    vector<int> leftCnt(n + 1, 0);
    vector<int> rightCnt(n + 1, 0);

    for (int i = 0; i < L; ++i) {
        int x;
        cin >> x;
        leftCnt[x]++;
    }

    for (int i = 0; i < R; ++i) {
        int x;
        cin >> x;
        rightCnt[x]++;
    }

    // 先消除已经存在的同品种左右匹配
    for (int i = 1; i <= n; ++i) {
        int matched = min(leftCnt[i], rightCnt[i]);
        leftCnt[i] -= matched;
        rightCnt[i] -= matched;
    }

    long long cntL = 0, cntR = 0;
    long long pairL = 0, pairR = 0;

    for (int i = 1; i <= n; ++i) {
        cntL += leftCnt[i];
        cntR += rightCnt[i];

        pairL += leftCnt[i] / 2;
        pairR += rightCnt[i] / 2;
    }

    long long answer = 0;

    // 左腿更多,优先处理左腿中的同品种对子
    if (cntL > cntR) {
        long long use = min(pairL, (cntL - cntR) / 2);
        answer += use;
        cntL -= 2 * use;
    }

    // 右腿更多,优先处理右腿中的同品种对子
    if (cntR > cntL) {
        long long use = min(pairR, (cntR - cntL) / 2);
        answer += use;
        cntR -= 2 * use;
    }

    // 剩余左右腿之间需要修改品种
    answer += min(cntL, cntR);

    // 数量多的一侧需要翻转
    answer += abs(cntL - cntR);

    cout << answer << '\n';

    return 0;
}

时间复杂度为 (O(n)),空间复杂度为 (O(n))。