题意:两个数组,长度一样。他们中有x个是一模一样,y个经过换序可以一样。给出长度n和x,y,再给出其中一个数组,问能不能有另一个数组符合要求。有就输出YES并打印这个数组,否则输出NO。
分析:以后我不做2500的题了,对自己太自信了。没有金刚钻,不去试这些玩意了。
首先对数组按数值从小到大排序,然后计算相同量,每个数和前一个数相同,相同量就是前一个数+1.然后按照相同量从大到小排序,把x的指标优先配发给相同量高的数。然后从没配发的(假设长度为len)开始按数值从小到大排序,配发值为a[i+len/2].val注意如果不分的话要加上已配发的数num再减去n(相当于没有配发的数绕成环)
令tmp=n-y;然后一一甄别这些数,要是配发的值和自己数值相等了,那就让他为额外的数(根据定义额外的数一定存在)tmp--。当tmp仍然存在的时候就选一些不被额外数替代的数变成这些值就可以了。
判no的条件是n-y+n-num<2*a[i].sam,因为这个情况下就算你把所有的值全部相等加上额外数,也抵消不掉相同的这么多。
一开始我想的是能不能先去x再去n-p,wa了不知道多少次。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=100005;
struct shu
{
int val;//代表值
int sam;//代表相同量
int pos;//代表位置
int cor;//代表对应值应该是多少
}a[N];
int ji[N];//记录有哪些数已经被用到了
int unuse[N];//还有这些数没有被用过
int cmp1(shu x1,shu x2)
{
return x1.val<x2.val;
}
int cmp2(shu x1,shu x2)
{
return x1.sam>x2.sam;
}
int cmp3(shu x1,shu x2)
{
return x1.pos<x2.pos;
}
int n,x,y;
void print()
{
sort(a,a+n,cmp3);
printf("YES\n");
for (int i=0;i<n;i++)
{
printf("%d ",a[i].cor);
}
printf("\n");
}
void rlmn()
{
scanf("%d%d%d",&n,&x,&y);
for (int i=0;i<=n+1;i++)
{
ji[i]=0;
}
for (int i=0;i<n;i++)
{
scanf("%d",&a[i].val);
a[i].pos=i;
a[i].sam=1;//代表初始的时候只和自己相同
a[i].cor=-1;
ji[a[i].val]=1;
}
//计算哪些颜色还没有被用过
int tmp=0;
for (int i=1;i<=n+1;i++)
{
if (ji[i]==0)
{
unuse[tmp++]=i;
}
}
//第一次排序,按大小排序,从而确定same数量
sort(a,a+n,cmp1);
for (int i=1;i<n;i++)
{
if (a[i].val==a[i-1].val)
{
a[i].sam=a[i-1].sam+1;
}
}
//第二次排序,按sam排序
sort(a,a+n,cmp2);
//用相同的指标x和额外数字的指标n-y来处理sam较大的一些数
tmp=n-y;int num;int len;
int flag=0;
for (int i=0;i<n;i++)
{
if (x>0)
{
a[i].cor=a[i].val;
x--;
continue;
}
if (n-i+n-y<2*a[i].sam)
{
printf("NO\n");
return;
}
num=i;len=n-i;break;//两个指标都用完了,代表着还有num个数需要周旋。
}
//第三次排序 ,按大小排序,这样就可以优先更换same大的
sort(a+num,a+n,cmp1);
for (int i=num;i<n;i++)
{
if (i+len/2<n)
a[i].cor=a[(i+len/2)].val;
else
a[i].cor=a[(i+len/2+num-n)].val;
}
tmp=n-y;
for (int i=num;i<n;i++)
{
if (a[i].cor==a[i].val)
{
a[i].cor=unuse[0];
tmp--;
}
}
for (int i=num;i<n;i++)
{
if (tmp>0&&a[i].cor!=unuse[0])
{
a[i].cor=unuse[0];
tmp--;
}
}
//最后一次排序,按地址排回来
print();
}
int main()
{
int T;
scanf("%d",&T);
while(T--)rlmn();
return 0;
}