Field Should Not Be Empty

发布时间 2023-12-26 19:05:37作者: Tx_Lcy

题目传送门

一种比较暴力的做法,不需要观察任何性质。

思路

首先特判一下 \(\forall i,p_i=i\) 的情况,输出 \(n-2\),不难发现剩下的情况必定需要交换两个数。

首先考虑\(a_i\) 表示 \(i\) 左边比 \(p_i\) 大的数的个数与 \(i\) 右边比 \(p_i\) 小的数的个数之和\(a\) 数组可以用树状数组简单求出。

我们发现此时的 \(f(p)\) 值即为满足 \(a_i=0\)\(i\) 的个数。

考虑若交换 \(i,j\),此时的 \(a\) 数组会如何变化。

\(A=p_i,B=p_j\),不难发现交换仅会在 \(A>B\) 时发生,且此时受到影响的位置必然 \(\in [i,j]\)

我们先不考虑 \(a_i\)\(a_j\) 的变化,只考虑 \((i,j)\) 内的数。

首先计算交换 \(A,B\) 后对每个位置左边比它大的数的个数的影响,不难发现会令 \(p_k \in (B,A)\) 的所有 \(a_k\) 减一。

然后计算交换 \(A,B\) 后对每个位置右边比它小的数的个数的影响,不难发现会令 \(p_k \in (B,A)\) 的所有 \(a_k\) 减一。

所以我们操作 \(i,j\) 对所有区间 \((i,j)\) 内的数的影响是令所有满足 \(p_k \in (p_j,p_i)\)\(a_k\) 减二。

接着特殊处理一下端点的贡献,不难发现 \(p_i\) 想要满足条件必须得从位置 \(i\) 被交换到位置 \(p_i\),这些位置一共只有 \(n\) 种,扫到的时候判一下就行了。

接下来我们继续尝试转化原问题。

不难发现,我们操作的 \(i,j\) 一定满足 \(p_i\) 是前缀最大值,\(p_j\) 是后缀最小值。

那么考虑扫描线,由于 \(p_i\) 递增,所以我们每次把上一个前缀最大值到当前前缀最大值之间的所有数扫入线段树内,同时每次把不满足条件的数踢出。此时已经消去了一维,由于每个数只会被加入一次,当某个数被加入的时候我们二分一下它可以对哪些后缀最小值产生贡献,然后在线段树上区间加就行了。

至此,本题成功被解决,时间复杂度 \(\mathcal O(n \log n)\)

代码

提交记录