Codeforces Global Round 14 D. Phoenix and Socks(贪心/好题)
To satisfy his love of matching socks, Phoenix has brought his n socks (n is even) to the sock store. Each of his socks has a color ci and is either a left sock or right sock.
Phoenix can pay one dollar to the sock store to either:
- recolor a sock to any color c′ (1≤c′≤n)
- turn a left sock into a right sock
- turn a right sock into a left sock
The sock store may perform each of these changes any number of times. Note that the color of a left sock doesn't change when it turns into a right sock, and vice versa.
A matching pair of socks is a left and right sock with the same color. What is the minimum cost for Phoenix to make n/2 matching pairs? Each sock must be included in exactly one matching pair.
Input
The input consists of multiple test cases. The first line contains an integer t (1≤t≤1000) — the number of test cases.
The first line of each test case contains three integers n, l, and r (2≤n≤2⋅10^5; n is even; 0≤l,r≤n;l+r=n) — the total number of socks, and the number of left and right socks, respectively.
The next line contains 𝑛n integers ci (1≤ci≤n) — the colors of the socks. The first l socks are left socks, while the next r socks are right socks.
It is guaranteed that the sum of n across all the test cases will not exceed 2⋅10^5.
Output
For each test case, print one integer — the minimum cost for Phoenix to make n/2 matching pairs. Each sock must be included in exactly one matching pair.
Example
input
Copy
4
6 3 3
1 2 3 2 2 2
6 2 4
1 1 2 2 2 2
6 5 1
6 5 4 3 2 1
4 0 4
4 4 4 3
output
Copy
2
3
5
3
不妨设l大于等于r。首先可以将l和r中颜色相同的凑成一对直接抵消掉,则剩下的l的颜色与r的颜色互不相同(但l中可能有多只同一个颜色的袜子,r同理)。然后考虑怎么给这些配对。如果l和r不相等,设d = l - r,容易知道d是偶数,则肯定有d / 2只左袜子要变成右袜子。一种可行的贪心策略是从l中找两只同样颜色的袜子,将其中一只变成右袜子(当然变完后也要消掉),这样不断处理,当d变为0或者没有两只及以上相同颜色的左袜子。此时若d不为0,则只能将l中的d只左袜子既变方向又变颜色(因为右袜子中和这些相同的颜色的袜子肯定在一开始就被消掉了),对答案贡献为2 * d。这时候l = r,剩下的左袜子右袜子数量相同颜色彼此不同,对答案的贡献为剩下的左/右袜子的数量。
//注意:代码模板中的代码将会被复制到任何新创建的文件中,编辑代码模板中的代码,让他帮你自动增加固定代码吧
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
int n, l, r, a[200005], a1[200005],b[200005],b1[200005];
int main(){
int t;
cin >> t;
while(t--) {
cin >> n >> l >> r;
for(int i = 1; i <= n; i++) a1[i] = b1[i] = 0;
for(int i = 1; i <= l; i++) {
cin >> a[i];
a1[a[i]]++;//用桶计数
}
for(int i = 1; i <= r; i++) {
cin >> b[i];
b1[b[i]]++;
}
for(int i = 1; i <= n; i++) {
int tmp = min(a1[i], b1[i]);
a1[i] -= tmp;//抵销
b1[i] -= tmp;
}
int ans = 0;
if(l >= r) {
int d = l - r;
d /= 2;
for(int i = 1; i <= n; i++) {
while(a1[i] >= 2 && d) {//贪心
a1[i] -= 2;
d--;
ans++;
}
while(a1[i] && b1[i]) {
a1[i]--;
b1[i]--;
}
}
if(d) ans += d * 2;
for(int i = 1; i <= n; i++) {
ans += b1[i];//因为上一步的操作没有在a1体现,此时a1和b1中的和不一样,必须以b1为准
}
} else {
int d = r - l;
d /= 2;
for(int i = 1; i <= n; i++) {
while(b1[i] >= 2 && d) {
b1[i] -= 2;
d--;
ans++;
}
while(a1[i] && b1[i]) {
a1[i]--;
b1[i]--;
}
}
if(d) ans += d * 2;
for(int i = 1; i <= n; i++) ans += a1[i];
}
cout << ans << endl;
}
}