【贪心】Codeforces Round #436 (Div. 2) D. Make a Permutation!
题意:给你一个长度为n的数组,每个元素都在1~n之间,要你改变最少的元素,使得它变成一个1~n的排列。在保证改动最少的基础上,要求字典序最小。
预处理cnt数组,cnt[i]代表i在原序列中出现的次数。b数组,代表没有出现过的数是哪些。b数组的长度就是答案。
b数组是从小到大排好的,然后for循环b数组,同时用一个指针p指着a数组的当前位置,最开始指向开头,如果cnt[a[p]]==1,就向后跳,否则再看 是否b[i]<a[p]或者a[p]这个数是否已经出现过了(用个hav数组表示a[p]是否已经再前面出现过了)。只要满足这两个条件之一,就可以让cnt[a[p]]--,然后把a[p]修改为b[i]。如此一定能保证字典序最小。
#include<cstdio> using namespace std; int n,a[200005],cnt[200005]; bool hav[200005]; int b[200005],e; int main(){ // freopen("d.in","r",stdin); scanf("%d",&n); for(int i=1;i<=n;++i){ scanf("%d",&a[i]); ++cnt[a[i]]; } for(int i=1;i<=n;++i){ if(!cnt[i]){ b[++e]=i; } } int p=1; for(int i=1;i<=e;++i){ while(cnt[a[p]]==1 || (!hav[a[p]] && b[i]>a[p])){ hav[a[p]]=1; ++p; } --cnt[a[p]]; a[p]=b[i]; } printf("%d\n",e); for(int i=1;i<n;++i){ printf("%d ",a[i]); } printf("%d\n",a[n]); return 0; }
——The Solution By AutSky_JadeK From UESTC
转载请注明出处:http://www.cnblogs.com/autsky-jadek/