开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第15天,点击查看活动详情
1515D - Phoenix and Socks
题意:给你n只袜子,有l只是左袜子,r只右袜子,每只袜子都有一个颜色c[i],你可以花费1个价值执行下列操作的任意一个:左袜子变为右袜子或者右袜子变为左袜子;将袜子的颜色变为任意一个颜色。问最少需要花费多少价值可以使得n只袜子左右匹配(话说袜子有左右之分吗,,,)
思路:显然一开始如果有相同颜色的左袜子和右袜子直接可以抹去,不会影响答案;剩下的左袜子和右袜子都是不能配对的,如果左袜子的数量等于右袜子的数量那么可以直接输出这个数量就可以,也就是把左袜子的颜色全变成和右袜子相等就可以;如果不相等,假设右袜子大于左袜子,那么先看看右袜子可不可以自己减少到和左袜子相等,在右袜子里面如果某个颜色的袜子数量大于1,就说明这种袜子是可以自己配对的,只要转成左袜子就行,然后讨论一下是否可以减到和左袜子相等,如果可以就是转左袜子的价值加上左袜子的数量,否则就是转左袜子的价值加上左右袜子数的差值再加上左袜子的数量;这个地方看代码就一目了然了
#include<bits/stdc++.h>
//#pragma-GCC-optimize("-Ofast");
#define ll long long
#define int long long
#define lowbit(x) ((x)&(-x))
#define endl '\n'
using namespace std;
const ll mod=998244353;
const ll inf=1e18;
const double pi=acos(-1);
const int N=1e6+100;
int t,n,lx[N],rx[N],tx[N],l,r;
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>t;
while(t--)
{
cin>>n>>l>>r;
for(int i=1;i<=n;i++) lx[i]=rx[i]=tx[i]=0;
for(int i=1;i<=n;i++)
{
int x;cin>>x;
if(i<=l) lx[x]++;
else rx[x]++;
}
l=0,r=0;
int lm=0,rm=0,ans=0;
for(int i=1;i<=n;i++)
{
int x=min(lx[i],rx[i]);
lx[i]-=x;rx[i]-=x;
l+=lx[i];r+=rx[i];
if(lx[i]&1) lm+=lx[i]-1;
else lm+=lx[i];
if(rx[i]&1) rm+=rx[i]-1;
else rm+=rx[i];
}
if(l==r) ans=l;
else
{
int tmp;
if(r>l) tmp=rm;
else tmp=lm;
int c=max(r,l)-min(r,l);
if(tmp>=c) ans+=c/2+min(r,l);
else
{
ans+=tmp/2;
c-=tmp;
ans+=c+min(r,l);
}
}
cout<<ans<<endl;
}
return 0;
}