Date:2021.12.30
题意:给定n个数,要将其变成①n个数的组合 ②字典序最小,最少几步。
思路:我们无非是将出现过>=2次的数变成别的数,而变成的数一定是未在原序列中出现过的,因此与原数只能是>或<关系,因此我们将没出现过的数存起来,用一个优先队列保证最小的在最前面,这样挨个更换完后字典序一定是最小的。但还有个问题,我们找到了当前出现多次的数,如果它 > 优先队列队头元素,那么一定会被换掉;但如果 < 怎么办?那么当前元素就固定位置在这里,并且标记一下这个元素已经用过,接着找即使再找到这个已标记元素值相同的元素,都给它更换掉,这样一定能保证字典序最小,换掉的一定是最恰当的且不会颠倒。
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5+10;
LL n,m,k,t;
LL a[N],cnt[N];
bool st[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
cnt[a[i]]++;
}
int ans=0;queue<LL>q;
for(int i=1;i<=n;i++)
if(cnt[i]==0) q.push(i);
for(int i=1;i<=n;i++)
{
if(cnt[a[i]]>1)
{
if(a[i]<q.front()&&!st[a[i]])
{
st[a[i]]=true;
continue;
}
else
{
cnt[a[i]]--;
a[i]=q.front();q.pop();
ans++;
}
}
}
cout<<ans<<endl;
for(int i=1;i<=n;i++) cout<<a[i]<<' ';
return 0;
}