[AGC014F]Strange Sorting

14 篇文章 0 订阅

题目

传送门 to AtCoder

题意概要
对排列 { a } \{a\} {a},每次将其中的前缀 max ⁡ \max max 放到序列末尾(保持原顺序),问多少次能够完成排序。

数据范围与提示
n ⩽ 2 × 1 0 5 n\leqslant 2\times 10^5 n2×105

思路

类似 0-1 principle \text{0-1 principle} 0-1 principle较小数对大数的相对顺序无影响,可暂时忽略。所以,应该只需要考虑 某个值域后缀中数字。为了方便,就用原序列 [ 1 , n ] [1,n] [1,n] 作为指代;它实际上是 [ x , n ] [x,n] [x,n],但 x x x 1 1 1 地位相同。

考虑将数字 1 1 1 去掉,得到的序列需要 t t t 次才能完成排序,即 [ 2 , n ] [2,n] [2,n] 的相对顺序正确。则原序列要么 t t t 次就完成排序,要么 ( t + 1 ) (t{+}1) (t+1) 次完成排序。

如何判断?最 n a i v e \rm naive naive 想法是,找到 1 1 1 此时位置。这不可能。它相当于维护整个序列的模样。如果能做到,就直接模拟了,还考虑啥呀!

看来不应求出绝对位置。或许只需判断 1 1 1 2 2 2 之前或是之后。然而也无迹可寻。

不知道这条性质与下面的构造,哪个是先被想出的:非首项做为前缀 max ⁡ \max max 出现后,永远不会成为首项。下一段给出证明。为了方便叙述,称前缀 max ⁡ \max max 元素为 H    ( high ) {\frak H}\;(\textrm{high}) H(high) 类数。

首项是 H \frak H H 类数。因此,若非首项元素 f f f H \frak H H 类数,前面必有更小的 H \frak H H 类数 v v v 。二者操作后相邻。想要 f f f 成为首项,需要把 v v v 移开。只能期待 v v v 不是 H \frak H H 类数而 f f f 是。而这仍是非首项元素 f f f H \frak H H 类数的情况,所以它前面仍有比自己更小的数。这就说明不可能了。

证明了这个,出题人就构造了个辅助数字:记 f f f [ 2 , n ] [2,n] [2,n] 中的数字在 ( t − 1 ) (t{-}1) (t1) 时刻最靠前的那个。不难验证 f ≠ 2 f\ne 2 f=2,因为此时再进行一次操作就能让 [ 2 , n ] [2,n] [2,n] 有序,且现在无序。根据定义, 2 2 2 f f f 之后。 1 1 1 就有可能在 f f f 之前、二者之间、 2 2 2 之后。

想要答案为 t t t,不难验证必须是 1 1 1 f f f 2 2 2 之间(不会在把 f f f 放到 2 2 2 后面的同时把 1 1 1 给带走)。只有 D D G \sf DDG DDG 的双眼才能看到下面这条判据——正是这双眼睛,把 O n e I n D a r k \sf OneInDark OneInDark 看得只有 18 c m 18\rm cm 18cm 高——三者的 圆排列 顺序不变。也就是说,认为 ⟨ a , b , c ⟩ \langle a,b,c\rangle a,b,c ⟨ b , c , a ⟩ \langle b,c,a\rangle b,c,a 相等,则 ⟨ 1 , 2 , f ⟩ \langle 1,2,f\rangle 1,2,f t t t 时刻之前亘古不变。而这也恰好足够确定 1 1 1 是否在 2 , f 2,f 2,f 之间,巧妙至极!

证明则只需要耐心。记非 H \frak H H 类数字为 L    ( low ) {\frak L}\;(\textrm{low}) L(low) 类数字。循环顺序改变,必然是从左到右 H , low , H {\frak H},\textrm{low},{\frak H} H,low,H L , high , L {\frak L},\textrm{high},{\frak L} L,high,L 。当 f f f 为首项时,其为 H \frak H H,而 1 , 2 1,2 1,2 都是 L \frak L L 了,无矛盾。当 f f f 不是首项时,由 性质 知其为 L \frak L L,尝试填出 L , high , L {\frak L},\textrm{high},{\frak L} L,high,L 会失败,另一种更会失败。

所以只需判断最初序列中 ⟨ f , 1 , 2 ⟩ \langle f,1,2\rangle f,1,2 是否为这种圆排列,就可以得到新的 t ′ t' t 了。而 f f f 的更新也同样简单,若 t t t 不变则 f f f 不变(因为此时顺序为 ⟨ f , 1 , 2 ⟩ \langle f,1,2\rangle f,1,2,非圆排列),否则 f = 2 f=2 f=2,即 t ′ − 1 = t t'-1=t t1=t 时刻的情况。

代码

注意 t = 0 t=0 t=0 时不应递推,因为 f f f 未定义。这样困难的题目,代码却寥寥数行……

#include <cstdio> // JZM yydJUNK!!!
int pos[200005];
int main(){
	int n; scanf("%d",&n);
	for(int i=1,x; i<=n; ++i)
        scanf("%d",&x), pos[x] = i;
	int t, f = n, j = n-1;
	for(; j&&pos[j]<=pos[f]; --j) f = j;
	if(!j) return void(puts("0")), 0;
	for(t=1; j!=1; --j) // only one operation needed
		if(!(pos[j] < pos[f] && (pos[j-1] < pos[j] || pos[f] < pos[j-1]))
		  && !(pos[f] < pos[j] && pos[f] < pos[j-1] && pos[j-1] < pos[j]))
			++ t, f = j; // j is 2 in solution
	printf("%d\n",t);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值