cf864 Round #436 Div2-D【贪心】

这篇博客讨论了一种算法问题,即如何通过最少的步骤将给定的n个数转换成字典序最小的组合。作者提出了一种解决方案,利用优先队列保存未出现过的数,并按字典序依次替换出现多次的数,确保字典序最小。在遇到小于优先队列头部的数时,会固定该位置并标记,后续相同数也会被替换,以保证字典序的最小化。代码实现中展示了详细的处理流程。
摘要由CSDN通过智能技术生成

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值