[ARC 102F]Revenge of BBuBBBlesort!

Atcoder ARC 102F

F:Revenge of BBuBBBlesort!

题意:

给你一个长度为\(n\)的排列\(A\),可以交换\((a_i,a_{i+1},a_{i+2})\)当且仅当\(a_i>a_{i-1}>a_{i-2}\),问\(A\)是否能经过一系列交换最后有序
\(1 \le n \le 300000\)

题解:

emmmm有大佬看错了题,于是就变成了毒瘤题
真是道神仙题。。看了题解才会,证明容易构造困难啊。
先构造\(B_i=[A_i=i]\)
有这个结论
如果B中有3个连续的0,则没有构造方案\((1)\)
定义一个序列是合法的,当其01交错且两端是0,特殊地,单独的0,1也是合法的
我们先极大化每个位置所在合法序列的长度,然后如果对于所有合法序列同时满足以下条件,则存在方案,对于一个\([l,r]\)
1.其中元素的值域也在\([l,r]\),要不然换不出去的
2.对于目标在左边的元素,对于任意的\(i < j\)满足\(a_i < a_j\) \((2)\)
3.对于目标在右边的元素,对于任意的\(i < j\)满足\(a_i < a_j\) \((2)\)
以下是口胡的证明:
\((1)\):
记这三个的位置是\((i-1,i,i+1)\)如果以\(i\)为中心转了,那么\(i\)就动不了了,\(i-1\),\(i+1\)同理
\((2)\):
这两个东西原理一样,一起证掉,按目标在左边的考虑
如果有一个 \(i <j\),但\(a_i > a_j\),那么\(a_j\)一定要跨过\(a_i\),但这显然不太可能。。

过程:

1A

代码:

#define GG {puts("No"); return 0;}
const int N=300010;
int n;
int a[N],b[N];
inline bool Check(int l,int r) {
	int lbd=0,rbd=0;
	for(int i=l;i<=r;i++) {
		if(b[i]<i) {
			// printf("%d\n",i);
			if(lbd>b[i] || (b[i]<l || b[i]>r)) return false;
			lbd=b[i];
		} else if(b[i]>i) {
			if(rbd>b[i] || (b[i]<l || b[i]>r)) return false;
			rbd=b[i];
		}
	}
	return true;
}
signed main() {
	read(n);
	for(int i=1;i<=n;i++)
		read(b[i]),a[i]=(b[i]==i);
	for(int i=2;i<n;i++) if(!a[i-1] && !a[i] && !a[i+1]) GG
	for(int i=1;i<=n;i++) {
		if(a[i]==0) {
			int now=1;
			int l=i,r=i;
			while((a[r]^now) && r<=n) ++r,now^=1;
			--r;
			if(!Check(l,r)) GG
			i=r;
		}
	}
	puts("Yes");
	return 0;
}

用时:20min

posted @ 2018-09-02 19:18  functionendless  阅读(614)  评论(0编辑  收藏  举报