codeforce-864D

codeforce-864D

题 意:给定一个大小为n,元素值大小为1 - n的数组,要求它的一个排列,要求元素值大小从1-n值出现一次,问最小的修改次数,并在最小的修改次数下,求出它的最小字典序。
输出范围:
2<=n<=2e5
1<=ai<=n
样例输入:

4
3 2 2 3

样例输出:

2
1 2 4 3 

思 路:关键点1 求出所缺少的元素,也就是最少的修改次数,关键点二,怎么使得他的字典序最小。对于每一个可以修改的值,也就是出现次数大于二的值,我们每次从中所缺少的元素中拿出一个最小的值x(用有限队列维护),从前往后扫一遍,如果x < 这个可以修改的值y,那么就直接替换,否则保留,如果y保留了,那么下次遇到y就必要用当前最小的值替换掉。就能得到最小的字典序,其实就是一个贪心。当前值是否替换,只取决于,当前最小值是否小于当前值,如果大于,显然现在替换,没有再次遇到的时候替换好。

收 获:用贪心的思路求的字典序。当然方法有很多。这只是一种

#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 2e5+5;
typedef long long ll;
int n;
int a[maxn];
int mp[maxn];
int mp1[maxn];
int mp2[maxn];
vector<int> vec1;
vector<int> vec2;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        mp[a[i]]++;
    }
    for(int i=1;i<=n;i++){
        if(!mp[i])vec2.push_back(i);
    }
    queue<int> que;
    sort(vec2.begin(),vec2.end());
    for(int i=0;i<vec2.size();i++){
        que.push(vec2[i]);
    }
    for(int i=1;i<=n;i++){
        if(mp[i] >=2) mp1[i] = 1;
    }

    for(int i=1;i<=n;i++){
        if(mp1[a[i]]){
            if(!mp2[a[i]]){
                int temp = que.front();
                if(temp < a[i]){
                    int orgin = a[i];
                    a[i] = temp;
                    que.pop();

                    mp[orgin]--;
                    if(mp[orgin] < 2){
                        mp1[orgin] = false;
                    }
                }else{
                    mp2[a[i]] = true;
                }
            }else{
                int temp = que.front();
                a[i] = temp;
                que.pop();
            }
        }

    }
    printf("%d\n",vec2.size());
    for(int i=1;i<=n;i++){
        printf("%d%c",a[i],i==n?'\n':' ');
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37129433/article/details/81105604