A. Meximum Array
题意:
每次把a序列前k个数的MEX值放进b序列中,然后删掉a序列的前k个数,重复操作,直到a数组为空。求字典序最大的b序列组成。
思路:
- 要使得b序列的字典序最大,那么先放入b序列的MEX值应该尽可能的大。所以我们第一次选取的MEX值应该是整个a序列可能的最大MEX值。
- 然后删掉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;
}