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 
#include 
#include 

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

你可能感兴趣的:(c++,AtCoder,乱搞)