题意:
给定一个 a 序列,当 a 非空时可以选择从 a 中切出前 k 个数字(有才行),这 k 个数字取一个 MEX,得出来的结果加给 b 序列,要求构造出的 b 序列满足字典序尽可能大
MEX 指最小的、不存在于该非负序列中的数字
思路:
贪心地去想,每次选出一个数字去补充进要切的序列,想要使 MEX 尽可能大(使 b 字典序大),显然尽可能填满序列
但若判断出怎么填都填不满序列,后面再把数加入序列并不能使得出的结果变大(有缝隙),如 :
6 0 1 2 4 5 6 //结果应该是 3 0 0 0 //2 取完后判断填满了序列,但如果后面有 3 的话显然还不能停止(直到把 3 加入序列能生成更大的 MEX) //所以需要判断一下,如果此后 3 怎么都出现不了了,这个序列 3 这个位置肯定有缝隙,MEX 就卡在 3 了,再加入数反而会浪费,所以直接取 MEX 加入 b 中 //继续以上流程,直到 a 空为止 //再给点智慧数据 10 3 2 1 0 4 3 1 0 2 1 //5 4 0
代码:
#include#include #include #define mem(a,b) memset(a,b,sizeof a) #define cinios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)) #define sca scanf #define pri printf #define ul (u << 1) #define ur (u << 1 | 1) #define fx first #define fy second //#pragma GCC optimize(2) //[博客地址](https://blog.csdn.net/weixin_51797626?t=1) using namespace std; typedef long long ll; typedef pair PII; typedef pair PI; const int N = 200010, M = 4000010, MM = N; int INF = 0x3f3f3f3f, mod = 1e9 + 7; ll LNF = 0x3f3f3f3f3f3f3f3f; int n, m, k, T, S, D; int a[N], b[N]; bool st[N]; map mp;//用一个map记录某数存在多少个 void solve() { cin >> n; k = 0; mp.clear(); st[0] = false;//多组注意清空 for (int i = 1; i <= n; i++) cin >> a[i], mp[a[i]]++, st[i] = false; //map记录数的个数 int bu = 0;//需要补的数是几 for (int i = 1; i <= n; i++) { st[a[i]] = true;//标记存在 while (st[bu])bu++;//此位置存在的话肯定不需要补数,找到要补的位置 mp[a[i]]--;//在此之后a[i]的个数-- if (!mp[bu]) { //一旦找不到能补的,再加数进来也不会影响 MEX //所以直接取 b[k++] = bu; for (int j = 0; j < bu; j++)//再随时清空,重置 st[j] = false; bu = 0; } } cout << k << 'n'; for (int i = 0; i < k; i++) cout << b[i] << ' '; cout << 'n'; } int main() { cinios; cin >> T; while (T--)solve(); return 0; }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)