Codeforces Round #762 (Div. 3) E. MEX and Increments


前言

  • 寒假开始搞一搞

题目

  • 原题地址:E. MEX and Increments
  • 题目编号:1619E
  • 目标算法:dp(动态规划)
  • 难度评分:1700

1.题目大意

  • 给你一个由n个非负数构成的数组
  • 定义MEX为数组中不存在的最小非负数,例如:
    • [3, 1, 0]      MEX = 2
    • [3, 3, 1, 4]  MEX = 0
  • 要求使MEX = 0到n需要对数组进行最小的操作次数,无法实现输出-1
  • (一次操作就是对数组中任意元素+1)

2.题目分析

  • 首先有几个注意要点
    1. 当前i对应的MEX不满足题意为-1时,后面大于i的数对应的MEX均为-1
    2. 当前i对应的MEX满足题意时,前面必然可以构造出一个小序列,满足0到i的元素有且只有一个。
    3. 构造小序列的最新一位i-1时,要从已构造元素的重复元素中选出最接近i-1的一个进行构造。
  • 根据要点2以及题目要求,我们可以得到以下公式:
  • ans = dp + cnt
  • 其中:
    • ans:要求的最小操作数
    • dp:构造小序列所需的最小操作数
    • cnt:当前数值元素的个数
  • 根据要点3,进一步添加2个优先队列:
    • up:升序,用于存储样例中的所有元素
    • down:降序,用于存储小于当前i的重复元素
  • 以样例中的0 1 2 3 4 3 2为例进行演示
MEX up down dp cnt ans
0 0 1 2 2 3 3 4 ? 0 1 0 + 1 = 1
1 1 2 2 3 3 4 0 1 - 1 - 0 + 0 = 0 1 0 + 1 = 1
2 2 2 3 3 4 1 2 - 1 - 1 + 0 = 0 1 0 + 1 = 1
3 3 3 4 2 2 3 - 1 - 2 + 0 = 0 2 0 + 2 = 2
4 4 3 3 2 4 - 1 - 3 + 0 = 0 2 0 + 2 = 2
5 ? 4 3 2 5 - 1 - 4 + 0 = 0 0 0 + 0 = 0
6 ? 3 2 6 - 1 - 3 + 0 = 2 0 2 + 0 = 2
7 ? 2 7 - 1 - 2 + 2 = 6 0 6 + 0 = 6
  • 得到最终答案1 2 2 1 0 2 6

3.题目代码

#include 
#include 
#include 

using namespace std;

int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        int n;
        int tmp;
        cin >>n;
        long long cnt[200005]={0};//有可能有大于n的数,所以数组要开到最大
        priority_queue,greater> up;//升序
        priority_queue,less> down;//降序
        for(int i=0;i> tmp;
            cnt[tmp]++;
            up.push(tmp);
        }
        long long dp = 0;//创造小序列的操作数
        long long ans = 0;
        cout << cnt[0] << " ";
        for(int i=1;i<=n;i++)
        {
            while(!up.empty()&&up.top()
  • ps:在做题的过程中发现对于0的特判可以直接包含进去,于是以上代码就是最后的版本