AtCoder Regular Contest 102F Revenge of BBuBBBlesort! 亂搞

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章