题意
给定一个 a 序列,当 a 非空时可以选择从 a 中切出前 k 个数字(有才行),这 k 个数字取一个最小的且不存在于该非负序列中的数字,得出来的结果加给 b 序列,要求构造出的 b 序列满足字典序尽可能大
样例:
2 2 3 4 0 1 2 0
要让字典序尽可能大,在第6位后面截一下,它之前的数字全都有,所以我们得到5,后面两位得到1.故答案是5 1
0 0 2 1 1 1 0 0 1 1
同理,返回3 2 2 0
思路:
要让字典序尽可能大,所以我们要让每一位的数字尽可能的大,且让数位尽可能多,可以贪心,同时数组应该尽可能全部用完。
标记一个cnt记录数字出现的次数,顺序遍历时,每次不断更新当前已经出现过的数,直到更新结果无法保持连续时,那么空出来的那个数字就是我们应该要填的了。
另外,如果发现某一个数字在当前是空缺却它之后不会再出现的话,那我们当然应该直接把它加入答案。把它留到后面并不会对我们有什么好处。
细节见代码;
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll t;
ll n;
ll cnt[200010];//记录每个数出现的次数
ll mas[200010];
ll vis[200010];//标记是否在当前已经被记录
int main()
{
cin>>t;
while(t--){
memset(vis,0,sizeof vis);
memset(mas,0,sizeof vis);
memset(cnt,0,sizeof cnt);
cin>>n;
ll ans[200010];
for(int i=1;i<=n;++i){
cin>>mas[i];
cnt[mas[i]]++;
}
ll bu=0;//记录需要补的数字
ll num=0;
for(int i=1;i<=n;++i){
vis[mas[i]]=1;//表示当前这个数已经出现
while(vis[bu]) bu++;
cnt[mas[i]]--;//此时代表再次之后mas【i】出现的次数
if(!cnt[bu])//之后不再有这个需要补的数字,所以这里选择直接把它加入答案
{
ans[++num]=bu;
for(int k=0;k<bu;++k) vis[k]=0;
bu=0;
}
}
cout<<num<<endl;
for(int i=1;i<=num;++i) cout<<ans[i]<<" ";
cout<<endl;
}
return 0;
}
本文介绍了一种算法,用于解决给定一个非负整数序列,如何通过特定规则构造出一个字典序尽可能大的新序列的问题。文章详细阐述了解决方案的思路,包括使用贪心策略和记录数字出现次数的方法。
541

被折叠的 条评论
为什么被折叠?



