【JZOJ5405】 Permutation

题目简述

你有一个长度为 n n 的排列P与一个正整数 K K

你可以进行如下操作若干次使得排列的字典序尽量小 。

对于两个满足|ij|K |PiPj|=1 | P i − P j | = 1 `的下标 i i j,交换 Pi P i Pj P j

n500000 n ≤ 500000

思路

整体感知

这道题与下标有关系,且数值唯一确定,那我们试试把下标和数值颠倒一下。

我们发现,这时的题目就转化成:

你有一个长度为 n n 的排列L与一个正整数 K K
你可以进行如下操作若干次使得排列的字典序尽量小 。
对于满足且|LiLi+1|k的下标 i i ,交换Li Li+1 L i + 1

那我们就要让小的数尽量靠前。

我们求出这个L序列,再转回答案序列就好了。

然后就有各种神奇地贪心或者随机化水法,可以拿很高分。

认真地思考

我们发现,如果有两个位置i,j,保证 i<j i < j ,如果 |aiaj|<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 LjLi<K L j − L i < K LkLi<K L k − L i < K ,那么肯定有 |LjLk|<K | L j − L k | < K

若把上述推论换成 Lj,Lk<Li L j , L k < L i 也成立。

这就说明了如果 i i 挡住j,k,在 Lj,Lk L j , L k 都大于或小于 Li L i 的情况下, j j 一定也挡住k,所以我们只表示 i i 挡住j j j 挡住k,而不用表示 i i 挡住k了。

所以,一个点其实只用连2条边即可,它分别连向它右边第一个比它大的,差值小于K的点,和第一个比它小的,差值小于K的点。这样,就可以表示所有限制。

很神奇吧。

这样全局就只有2n个限制了。

复杂度: O(nlogn) O ( n l o g n )

总结

  • 序列上构造问题可以考虑连边表示限制
  • 用等效且更少的连边来优化时间
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值