[BZOJ2124]等差子序列/[CF452F]Permutation

[BZOJ2124]等差子序列/[CF452F]Permutation

题目大意:

一个\(1\sim n\)的排列\(A_{1\sim n}\),询问是否存在\(i,j(i<j)\),使得\(A_i<A_j\)\(\frac{A_i+A_j}2\)\(i,j\)之间出现。

BZOJ上的数据范围:\(n\le10000\);
CF上的数据范围:\(n\le3\times10^5\)

思路:

从左到右枚举每一个数,用两个布尔数组\(b_0,b_1\)分别维护数值为\(i\)的数是否在当前数的左边、右边出现。然后将与当前数差值相等的位置对应起来(如,当前\(A_i=3\)时,将\(b_{0,1}\)\(b_{1,5}\)对应起来),看一下对应位置有没有都是\(1\)的,如果有,则说明存在。

使用bitset优化可以做到\(\mathcal O(\frac{n^2}{32})\),但还是过不了。

发现如果只用一个数组\(b\)维护左边出现过的数,那么对于当前位置\(i\),若以\(b_{A_i}\)为中心的极大字符串是不是回文串,说明一个在左边出现,一个在右边出现,那么一定存在解。而确定中心的回文串判定可以用树状数组维护哈希实现。

事件复杂度\(\mathcal O(n\log n)\)

源代码:

#include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
	register char ch;
	while(!isdigit(ch=getchar()));
	register int x=ch^'0';
	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
	return x;
}
const int N=300001;
const unsigned base=13;
unsigned pwr[N];
int n;
class FenwickTree {
	private:
		unsigned val[N];
		int lowbit(const int &x) const {
			return x&-x;
		}
		unsigned query(const int &p) const {
			unsigned ret=0;
			for(register int i=p;i;i-=lowbit(i)) {
				ret+=val[i]*pwr[p-i];
			}
			return ret;
		}
	public:
		void modify(const int &p) {
			for(register int i=p;i<=n;i+=lowbit(i)) {
				val[i]+=pwr[i-p];
			}
		}
		unsigned query(const int &l,const int &r) const {
			return query(r)-query(l-1)*pwr[r-l+1];
		}
};
FenwickTree t[2];
int main() {
	n=getint();
	for(register int i=pwr[0]=1;i<=n;i++) {
		pwr[i]=pwr[i-1]*base;
	}
	bool ans=false;
	for(register int i=1;i<=n;i++) {
		const int x=getint();
		const int len=std::min(x-1,n-x);
		ans|=t[0].query(x-len,x-1)!=t[1].query(n-x-len+1,n-x);
		t[0].modify(x);
		t[1].modify(n-x+1);
	}
	puts(ans?"YES":"NO");
	return 0;
}
posted @ 2018-09-13 09:38  skylee03  阅读(157)  评论(0编辑  收藏  举报