• 【贪心】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
    ",e);
    	for(int i=1;i<n;++i){
    		printf("%d ",a[i]);
    	}
    	printf("%d
    ",a[n]);
    	return 0;
    }
  • 相关阅读:
    【BZOJ4566】[HAOI2016]找相同字符
    【BZOJ3238】[AHOI2013]差异
    【BZOJ4698】[SDOI2008]Sandy的卡片
    后缀数组(SA)总结
    【HDU3117】Fibonacci Numbers
    线性常系数齐次递推总结
    【HDU4565】So Easy!
    【BZOJ3144】[HNOI2013]切糕
    【BZOJ1070】[SCOI2007]修车
    【LOJ6433】【PKUSC2018】最大前缀和
  • 原文地址:https://www.cnblogs.com/autsky-jadek/p/7596253.html
Copyright © 2020-2023  润新知