题目简述
你有一个长度为 n n 的排列与一个正整数 K K 。
你可以进行如下操作若干次使得排列的字典序尽量小 。
对于两个满足 且 |Pi−Pj|=1 | P i − P j | = 1 `的下标 i i 与,交换 Pi P i 与 Pj P j 。
n≤500000 n ≤ 500000
思路
整体感知
这道题与下标有关系,且数值唯一确定,那我们试试把下标和数值颠倒一下。
我们发现,这时的题目就转化成:
你有一个长度为
n
n
的排列与一个正整数
K
K
。
你可以进行如下操作若干次使得排列的字典序尽量小 。
对于满足且的下标
i
i
,交换与
Li+1
L
i
+
1
。
那我们就要让小的数尽量靠前。
我们求出这个L序列,再转回答案序列就好了。
然后就有各种神奇地贪心或者随机化水法,可以拿很高分。
认真地思考
我们发现,如果有两个位置i,j,保证 i<j i < j ,如果 |ai−aj|<K | a i − a j | < K ,那么,无论怎么变化, ai a i 这个数都会在 aj a j 的左边,而不会跑到右边去。
形象地想,就是我们当然希望更小的aj跑到左边,但由于可恶的 ai a i 像一堵墙一样堵着,使 aj a j 只能在 ai a i 右边。
这些所谓的“墙”其实就是构造的限制,如何把这些限制表示出来呢?
连边!
那么,我们就把每个点往所有在它右边且与它差值小于K的点连单向边,表示一堵“墙”。
如果一个数(点)入度为0,那么它就可以放在最左边,而显然我们要把最小的数放在左边。
我们每次就找到当前入度为0的最小的数(点),保证它,即这个数(点)已经没有什么数(点)必须在它左边了,那么当前位置就选它。它所带来的限制也随之消失,就再把它连出的边全部删掉。不断重复此过程。
这样的复杂度是: O(n2) O ( n 2 ) 的
继续优化
我们发现,如果有三个位置 i,j,k i , j , k , i<j<k i < j < k , Lj,Lk>Li L j , L k > L i , Lj−Li<K L j − L i < K , Lk−Li<K L k − L i < K ,那么肯定有 |Lj−Lk|<K | L j − L k | < K 。
若把上述推论换成 Lj,Lk<Li L j , L k < L i 也成立。
这就说明了如果 i i 挡住,在 Lj,Lk L j , L k 都大于或小于 Li L i 的情况下, j j 一定也挡住,所以我们只表示 i i 挡住和 j j 挡住,而不用表示 i i 挡住了。
所以,一个点其实只用连2条边即可,它分别连向它右边第一个比它大的,差值小于K的点,和第一个比它小的,差值小于K的点。这样,就可以表示所有限制。
很神奇吧。
这样全局就只有2n个限制了。
复杂度: O(nlogn) O ( n l o g n )
总结
- 序列上构造问题可以考虑连边表示限制
- 用等效且更少的连边来优化时间