A. Meximum Array 767 Div 1
作者:互联网
题目分析:我们先分析一下这道题目要我们做什么,我们会得到一个长度为n的序列,然后我们可以随机挑取前k个数字并找出其MEX的值放入b中,并把这前k个数删掉,然后继续操作,要求我们最后得到的b序列的字典序最大;
·解释一下:首先什么是MEX呢? 就是找出这一段序列中第一个未出现的自然数;
·什么是b的字典序,这个在Trie树那里已经讲过了,所以就不再赘述了;
题解:
这种题是让我们通过operation来得到b,并且b中的字典序要尽可能地大,所以这就不可避免的要用到贪心的思想,并且要掌握每个b中数字是怎么来的;
·我们可以发现b中存的数,都是MEX的值,也就是说b中的数是前k个数中第一个没出现的自然数;
所以每一次给b入一个值,都需要去从0开始往后看第一个没出现的自然数是什么;
(这里证明一下,放入b的一定是第一个未出现的自然数吗,它后面的数可不可能呢? 如果该自然数b[i] 未出现说明的是在这一整个序列中就压根没出现过这个数,那么不管我们取前面的几k个数,得到的MEX一定小于等于b[i]; 而且出于贪心的思想,我要让字典序越大越好,就是说我不在乎的是这个序列b的长度,而是在给每一个b入值的时候,我都尽可能让当前的b[i]最大)
·接下来问题就变成了,我们该如何去确定第一个未出现的自然数,我们自然而然的想到了记录数字的位置,而且是每一个位置(因为我们每一次都是证明i这个数存在于之后的序列中,所以不能只存储i的某一个位置);
·我们一开始就想到了和拓扑排序一样,用vector来模拟一个二维数组,第一维表示0~n的数,第二维存储的是对应的数的位置;
·接下来我们肯定是要让b越大越好,于是原有的序列本身我是要取完的,所以我用双指针,u和k,分别记录的是序列的起始位置和终止位置,k会随着能取到的数的右边界扩展到最右边的地方,那么对于原有序列的遍历就用这个循环条件表示while(u != n + 1) ; 然后取MEX的操作,我就是要枚举0~n的所有数,
直到找到第一个未出现的自然数时,我们令v = i ,然后退出循环,这里就是可以给b入第一个数了! 然后u和k都要更新!!!
·最后的答案就存储在了b数组中,并且我们用一个cnt来表示了数组的长度;
However! 在第二个样例的时候爆时间了!
·通过检查和人肉Debug,我们可以发现,如果整个原有序列中的数都时0,1,2,3这样很少的数据时,我用vector存储的位置就会很多,并且每次入一个b值,所消掉的元素个数也不多,但是我们每次在找MEX的时候,就会有很多时间浪费在已经被删掉的元素位置上,而且这个缺点越到后面影响越大,所以我们就要想到:不要重复的去看那些不可能出现的数值了! 可是vector不容易删除元素,所以我们就要利用单链表来表示,这样的话就会把重复的搜索给删除掉!
代码:
Submission #152993777 - Codeforces
启示:选好数据结构真的很重要,可以有效地降低时间复杂度;要熟练利用双指针算法!
标签:位置,第一个,自然数,MEX,Meximum,序列,Array,我们,Div 来源: https://www.cnblogs.com/ZheyuHarry/p/16118710.html