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;
}