- 给定一个长度为(n)的排列,一次操作可以选择一个(i)满足(p_{i-1}>p_i>p_{i+1}),然后交换(p_{i-1})和(p_{i+1})。
- 要求判断是否能把这个排列转化为(1,2,...,n)。
- (nle3 imes10^5)
重要结论
我们只可能选择一开始就满足(p_i=i)的位置操作,证明就考虑反证。
对于一个(p_i ot=i)的位置,如果我们操作了它,就会导致(p_{i-1}<p_i<p_{i+1})。
以(p_i<i)的情况为例,我们想要把它向左移,就必须操作(i-2)使得(p_{i-1}>p_i),那么就必然导致(p_{i-2}<p_{i-1}),因此不可能再把(i)往左移了,必然无解。
对于一个若干次操作后(p_i=i)的位置,则这个位置必然是跟(p_{i-2})或(p_{i+2})交换来的。
若跟(p_{i-2})交换来则(p_i>p_{i-1}),若跟(p_{i+2})交换来则(p_i<p_{i+1}),不可能满足(p_{i-1}<p_i<p_{i+1}),无法操作。
区间划分+推结论
根据先前的结论,如果有三个连续位置都满足(p_i ot=i),那么中间的位置始终无法被交换到,肯定无解。
否则,我们可以把连续一段(01010...010)取出来,当做一个独立的区间处理。
考虑判断一个区间([l,r])是否有解,首先一个必要条件就是所有数都必须在([l,r])范围内。
然后我们还需要一个条件,就是仅保留(p_i ot=i)的位置时最长下降子序列长度不能超过(2)。
首先这是必要的,因为存在一个长度为(3)的下降子序列时,肯定无法让它们全部到自己位置上。
其实这是充分的,因为一次交换让相邻两个元素变得有序,不可能使得最长下降子序列变大,那么当它长度变为(1)时就达成了条件。
代码:(O(n))
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 300000
using namespace std;
int n,p[N+5];
namespace FastIO
{
#define FS 100000
#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
char oc,FI[FS],*FA=FI,*FB=FI;
Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
}using namespace FastIO;
int f[2];I void Solve(CI l,CI r)
{
#define NA() (puts("No"),exit(0),0)//无解
if(l>r) return;RI i,Mn=n,Mx=1;for(i=l;i<=r;i+=2) Mn=min(Mn,p[i]),Mx=max(Mx,p[i]);(Mn^l||Mx^r)&&NA();//如果值不全在[l,r]范围内无解
for(f[0]=f[1]=0,i=l;i<=r;i+=2) p[i]>f[0]?f[0]=p[i]:(p[i]>f[1]?f[1]=p[i]:NA());//维护最长下降子序列判断长度是否会超过2
}
int main()
{
RI i,j;for(read(n),i=1;i<=n;++i) read(p[i]);
for(i=1;i+2<=n;++i) if(p[i]^i&&p[i+1]^(i+1)&&p[i+2]^(i+2)) return puts("No"),0;//连续三个p[i]≠i无解
for(i=1;i<n;++i) if(p[i]^i&&p[i+1]==i+1) {for(j=i;i+2<=n&&p[i+1]==i+1&&p[i+2]^(i+2);i+=2);Solve(j,i);}//抠出每段区间处理
return puts("Yes"),0;
}