MEX-A. Meximum Array

链接

A. Meximum Array

题意:
每次把a序列前k个数的MEX值放进b序列中,然后删掉a序列的前k个数,重复操作,直到a数组为空。求字典序最大的b序列组成。

思路:

  1. 要使得b序列的字典序最大,那么先放入b序列的MEX值应该尽可能的大。所以我们第一次选取的MEX值应该是整个a序列可能的最大MEX值。
  2. 然后删掉a序列中取得最大MEX值的长度为k的前缀,仍然选取剩余序列中最大的MEX值,重复操作。

关键问题:1. 如何找到当前序列最大的MEX值

  • cnt[i]:预处理数字出现的次数。注意cnt[]数组是动态变化的,每次访问一个值a[i],就执行了cnt[a[i]]--的操作,cnt[]始终代表的是数组a当前元素后面的值出现的次数统计
  • vis[a[i]]:标记某个数是否出现过。这个不能预处理,需要从前向后维护
  • mex:维护到当前位置,mex值是多少。
  • 每当cnt[tmp]==0时,就是说这个mex值,在数组a后面没有出现过了,这个就是最大的mex值,把它加到ans结果中。

所谓的删除前缀k的操作在a数组中也不用真的进行,只需要每得到一个最大的MEX值就开始重新计算最大MEX值即可。

int mex=0;
for(int i=1;i<=n;i++)
{
	vis[a[i]]=true;	//标记a[i]出现过
	while(vis[mex]) mex++;		//维护前缀的mex值,只要当前值出现了,mex就要向上加
	cnt[a[i]]--;	//当前数字遍历后需要删除。因为如果去掉这个数字后,mex值
	if(cnt[mex]==0)		//后面没有当前的mex值了
	{
			ans.push_back(mex);
			vis=vector<boo>(n+1,false);		//前缀全部删除,重新计算最大MEX值,初始化
			mex=0;
	}
#include<iostream>
#include<vector>
using namespace std;

const int N=2e5+100;
int a[N];

int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int n;
		cin>>n;
		
		//之所以把定义直接写在里面,是为了避免多组数据之间遗留重复,相互影响(否则也要每次进行清空操作)
		vector<int>ans;
		vector<int>cnt(n+1);
		vector<bool>vis(n+1,false);
		
		for(int i=1;i<=n;i++)
		{
			cin>>a[i];
			cnt[a[i]]++;
		}
		
		int mex=0;
		
		for(int i=1;i<=n;i++)
		{
			vis[a[i]]=true;
			while(vis[mex]) mex++;
			cnt[a[i]]--;
			if(cnt[mex]==0)
			{
				ans.push_back(mex);
				//重新找MEX值
				mex=0;
				vis=vector<bool>(n+1,false);	
			}
		}
		
		cout<<ans.size()<<endl;
		for(int i=0;i<ans.size();i++)
		cout<<ans[i]<<" ";
		cout<<endl;
	}
	
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值