题目链接
题目大意:
对于1–n号人给出了ai且i!=ai,他们希望bi=ai,问我们能够使得最多多少人满足条件的,并且输出构造一个错排序列使得任意bi!=i 且满足的人最多。
解题思路:
(不妨令每个人分配到的另一个bi视为颜色)
其实很简单,对于已经出现的ai,这种颜色是必然要满足它的,那么我们就会剩下若干个序号没有分配颜色,若干种颜色没有被使用。特殊情况就是存在若干对 (序号=颜色)的组,我们需要错位安排这些组。剩下的没使用的点与颜色就可以任意放了。还有个特殊情况,那就是(序号=颜色)只有一组,我们需要找到与该序号ai值一样的某个 a[pos] 去交换两者的颜色即可。
我用b数组保存答案,bi表示第i个人的答案
c数组表示 ci =1则i颜色已经被使用了
rnm存 未使用的颜色=未使用的点
ll a[222222];
ll b[222222];
ll c[222222];
vector<ll>s;
vector<ll>g;
vector<ll>p;
vector<ll>rnm;
vector<ll>lcj;
vector<ll>lck;
signed main()
{
ll t;
read(t);
while(t--)
{
ll n;
read(n);
ll ma=0;
for(int i=1; i<=n; i++)
{
read(a[i]);
if(c[a[i]]==0)
{
ma++;
c[a[i]]++;
b[i]=a[i];
continue;
}
g.push_back(i);
p.push_back(i);
//p.insert(i);
}
for(int i=1; i<=n; i++)
{
if(c[i])
continue;
else
{
if(b[i]==0)
{
rnm.push_back(i);
}
s.push_back(i);
}
}
ll fuck=rnm.size();
if(fuck>=1)
{
for(int i=0; i<rnm.size(); i++)
{
b[rnm[i]]=rnm[(i+1)%fuck];
//printf("?? %lld\n",rnm[i]);
c[rnm[(i+1)%fuck]]++;
}
}
for(int i=0; i<s.size(); i++)
{
if(c[s[i]]==0)
{
lcj.push_back(s[i]);
}
if(b[p[i]]==0)
{
lck.push_back(p[i]);
}
}
for(int i=0; i<lcj.size(); i++)
{
b[lck[i]]=lcj[i];
}
if(rnm.size()==1)
{
for(int i=1; i<=n; i++)
{
if(a[i]==a[rnm[0]]&&i!=rnm[0])
{
swap(b[i],b[rnm[0]]);
break;
}
}
}
printf("%lld\n",ma);
for(int i=1; i<=n; i++)
{
printf("%lld ",b[i]);
b[i]=0;
c[i]=0;
}
printf("\n");
s.clear();
g.clear();
rnm.clear();
p.clear();
lcj.clear();
lck.clear();
}
}