#10073. 卖匹配羊腿 题解
卖匹配羊腿 题解
你的代码主要有一个贪心错误:
不能把所有同侧、同品种的两只腿都立即翻转。
只有当某一侧的剩余腿数量多于另一侧时,才应该优先利用这一侧的同品种腿对。否则可能增加操作次数。
例如:
左腿:A A
右腿:B B
直接把两只左腿改成 B,需要 2 次操作;如果先翻转一只左腿,再处理,反而需要 3 次。
正确做法如下。
- 先消除同品种的左右腿匹配,不需要手术。
- 统计剩余的左腿数
cntL和右腿数cntR。 - 如果
cntL > cntR,只使用左腿中同品种成对的部分,每一对翻转一只,代价为 1。 - 如果
cntR > cntL,对右腿做同样处理。 - 剩余的左右腿需要进行品种修改,数量为
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))。