题目链接: Phoenix and Socks
大致题意
给你n只袜子, 有l只左袜子, r只右袜子. 每只袜子有颜色c.
你可以执行两种操作:
① 左袜子变成右袜子, 右袜子变成左袜子
② 把这个袜子改成任意一种颜色
问: 最少执行多少次操作, 使得n只袜子可以相互配对(一左一右, 且颜色相同)
解题思路
贪心 + 思维
首先我们明确一点, 如果此时我们都是一种类型的袜子(不妨认为是左袜子), 此时他们的颜色还都不一样, 那么我们必然需要操作2次, 才能使得袜子成功配对一对.
除此之外, 如果不同类型的袜子, 且颜色不同, 操作1次. 如果相同颜色且同类型袜子,操作1次.
到此, 我们的思路就已经有了, 对于本身已经配对的袜子, 我们直接移除不看即可.
对于余下的袜子, 假设有左袜子lnum双, 右袜子rnum双.
① 若lnum == rnum, 我们修改颜色使它们配对即可, 花费为lnum.
② 若lnum != rnum, 我们不妨假设左袜子多, 我们希望使得多余的部分左袜子, 如果把它变成右袜子, 直接可以配对. 这样我们可以避免操作2次的情况. 你会发现, 如果某种颜色的左袜子不止一双, 我们才可以通过1次操作使其配对.
当然我们也有可能仍会余下左袜子(最坏的情况就是左袜子每种颜色都是1只), 那我们不得不花费2次操作, 使得其配对.
代码方面还是有一些细节的, 处理好就可以快乐AC啦!
AC代码
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 2E5 + 10;
int l[N], r[N]; //记录每种颜色的左袜子/右袜子 只数.
int main()
{
int t; cin >> t;
while (t--) {
int n, lnum, rnum; scanf("%d %d %d", &n, &lnum, &rnum);
rep(i, n) l[i] = r[i] = 0;
rep(i, lnum) {
int x; scanf("%d", &x);
l[x]++;
}
rep(i, rnum) {
int x; scanf("%d", &x);
l[x] ? l[x]-- : r[x]++; //抵消掉已经配对的情况
}
int res = 0; int left = 0, right = 0;
rep(i, n) left += l[i], right += r[i]; //可以保证, l[i]和r[i]不同时存在
int cha = abs(right - left); //左右袜子差值的数目, 一定是偶数
rep(i, n) {
int can = (left > right ? l[i] : r[i]) / 2; //判断下是哪种袜子多
int pro = min(cha, can * 2); //提供的袜子数目
res += pro / 2;
cha -= pro;
}
res += min(left, right) + cha; //此时剩下的cha也一定是偶数, 我们会配对出cha / 2对, 花费为cha.
printf("%d\n", res);
}
return 0;
}