Description
给一个n排列p[],若存在一个位置i使得p[i-1]>p[i]>p[i+1],那么就可以交换p[i-1]和p[i+1]
Solution
真·感性乱搞+分类讨论
首先记a[i]=[p[i]=i],那么我们可以把p分成若干段01交替出现、首尾皆为0的子串。由交换性质可知这些段之间互不影响,即交换不会跨过这些段
考虑一整段[l,r]什么情况会No。
如果出现了最大值大于r或最小值小于l肯定不行,因为我们不能把它交换出去。
由于每次交换的两个位置奇偶性相同,那么每个位置上的数字也要和下标奇偶性相同。这个好像比较显然
还有就是,我们不会让一个数字先往左换、再往右换,并且方向相同的两个数相对位置不会改变。由交换性质可知数字的交换方向一定是单向的,而相对位置改变意味着某个数反向交换了
于是瞎搞就可以了,每个位置只会访问一次所以是O(n)的
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
const int INF=0x3f3f3f3f;
const int N=2000005;
int a[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
bool check(int l,int r) {
int mx=0,mn=INF;
rep(i,l,r) {
mx=std:: max(mx,a[i]);
mn=std:: min(mn,a[i]);
}
if (mn<l||mx>r) return true;
int r1=0,r2=0;
rep(i,l,r) if (a[i]!=i) {
if (a[i]<i) {
if (r1<a[i]) r1=a[i];
else return true;
} else {
if (r2<a[i]) r2=a[i];
else return true;
}
}
return false;
}
int main(void) {
int n=read(),x;
rep(i,1,n) a[i]=read();
rep(i,1,n) if (a[i]!=i) {
for (x=i;a[x+1]==x+1&&a[x+2]!=x+2;) x+=2;
x=std:: min(x,n);
if (check(i,x)) return puts("No"),0;
i=x;
}
return puts("Yes"),0;
}