C. Ehab and Prefix MEXs(ranting 1600)超详细题解

文章提供了对codeforces上ranting1600分题目的详细解答,主要讨论了一种数组构造问题,解析了无解的情况和有解时的构造策略,并给出了AC代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C. Ehab and Prefix MEXs(ranting 1600)超详细题解



前言

本系列的意义在于两点,一则是作为本人(一个编程初学者)的学习笔记记录,二则希望能对后来者提供一些帮助,因为本人也为新手,难免有些错误或讲述不清之处,恳请大家指出或提出建议,本人也会虚心修改。

本系列的目标是帮助大家解决一些codeforces上,ranting1600+(或者之后会改为1300+,看博主水平吧)的题目


一、题目及翻译

1. 原题(贴图)

Alt
【戳我跳转到题目】

2. 翻译
  1. 机翻版
    Alt
  2. 省流版
    对于每个测试数据给定的数组a,我们需要构造一个数组b使得b中由 b 1 b_1 b1, b 2 b_2 b2 , b 3 b_3 b3 … \dots b i b_i bi所构成的集合中不包含的最小非负整数为 a i a_i ai

二、解析及AC代码

1.解析

我们先讨论一下无解的情况:

  1. 如果数组A中元素不是按递增顺序排列。为什么呢 ? 不难想到如果数组A中元素不是按递增顺序排列,那么必然有 a j a_j aj> a k a_k ak(j<k),那么在i=j时,b中必然会有比 a j a_j aj更小的 a k a_k ak,那么当i==k时, a k a_k ak已经出现了,导致非法
  2. 如果 a j a_j aj>j。为什么呢? 因为当i==j时,b中最多有j个元素,而 a j a_j aj>j,那么就必然会有0( b 1 b_1 b1=1)或者j( b 1 b_1 b1=0)满足题意,而与集合中不包含的最小非负整数为 a i a_i ai相悖。

如果题目不是以上两种情况则有解,那么怎么构造出解呢?首先,当( a 1 a_1 a1=0)我们令( b 1 b_1 b1=1),而( a 1 a_1 a1=1)时我们令( b 1 b_1 b1=0)。然后从贪心的角度思考,因为a递增,为了使集合中不包含的最小非负整数为 a i a_i ai,那么我们必然要先把a[i-1]消耗掉。但如果a[i-1]==a[i],那么我们就尽可能按顺序把a中没有出现过的数字都先消耗掉。

那么,此时同学们就可以自己去尝试一下了,如果还是不太理解,可以参考下博主下面的AC代码

2.AC代码
#define _CRT_SECURE_NO_WARNINGS 01

#include<iostream>
#include<algorithm>

using namespace std;

const int N = 1e6 + 10;

int n, t, k;
int a[N], A[N], b[N];
bool st, vis[N];

int main()
{
  scanf("%d", &n);
  for (int i = 1; i <= n; i++)
  {
  	cin >> a[i];
  	A[i] = a[i];
  	vis[a[i]] = true;//标记a中出现过的数
  }
  sort(A + 1, A + 1 + n);
  for (int i = 1; i <= n; i++)
  {
  	if (a[i] > i || a[i] != A[i])//判断是否无解
  	{
  		st = true;
  		break;
  	}
  }
  if (st)//无解
  {
  	puts("-1");
  	return 0;
  }
  if (a[1] == 0)
  {
  	while (vis[k])
  		k++;//k存下一个应该历遍的数
  	b[1] = k++;
  }
  else b[1] = 0, k = 1;
  for (int i = 2; i <= n; i++)
  {
  	if (a[i] == a[i - 1])//a[i-1]==a[i]的情况
  	{
  		while (vis[k])
  			k++;
  		b[i] = k++;
  	}
  	else
  	{
  		b[i] = a[i - 1];//消掉a[i-1]
  	}
  }
  for (int i = 1; i <= n; i++)
  {
  	printf("%d", b[i]);
  	if (i != n)cout << ' ';
  }
  return 0;
}

如果觉得有用还请点个赞吧,拜托拜托

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值