其他分享
首页 > 其他分享> > P2757题解

P2757题解

作者:互联网

题目传送门
题意简述:一个排列,求是否存在长度\(\ge3\)的等差子序列。
如果存在长度\(>3\)的数列,那肯定存在长度为\(3\)的数列。设其为\(p_1,p_2,p_3\)
显然\(p_2-p_1=p_3-p_2\),即\(p_1,p_3\)关于\(p_2\)对称,且它们在\(p_2\)的两侧。
序列为一个排列,这是一个很重要的性质。
也就是说,如果不存在,则对于任意\(a_i\),\(a_i+k,a_i-k\)始终在\(p_i\)的同侧。
当遍历到第\(i\)个数时,将\(a_i\)加入一个序列中。
那么如果没有符合题意的数列,序列始终关于当前\(a_i\)对称,即\(a_i+k,a_i-k\)要么同时出现在左侧,要么同时在右侧。
用线段树维护区间哈希值。
完了。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 500001
#define mod 1000000007
#define bas 37
struct d{
	ll v;int l;
}ta[N<<2],tb[N<<2];
int T,n;
ll p[N];
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (l+r>>1)
d mg(d x,d y){
	d z;z.v=(x.v*p[y.l]%mod+y.v)%mod;
	z.l=x.l+y.l;return z;
}
void pushup(int p){
	ta[p]=mg(ta[lc],ta[rc]);
	tb[p]=mg(tb[rc],tb[lc]);
}
void build(int p,int l,int r){
	if(l==r){ta[p].l=tb[p].l=1;ta[p].v=tb[p].v=0;return;}
	build(lc,l,mid);build(rc,mid+1,r);pushup(p);
}
void c(int p,int l,int r,int pos){
	if(l==r){ta[p].v=tb[p].v=1;return;}
	if(pos<=mid)c(lc,l,mid,pos);else c(rc,mid+1,r,pos);
	pushup(p);
}
d q1(int p,int l,int r,int L,int R){
	if(L<=l&&r<=R)return ta[p];
	if(R<=mid)return q1(lc,l,mid,L,R);
	if(L>mid)return q1(rc,mid+1,r,L,R);
	return mg(q1(lc,l,mid,L,R),q1(rc,mid+1,r,L,R));
}
d q2(int p,int l,int r,int L,int R){
	if(L<=l&&r<=R)return tb[p];
	if(R<=mid)return q2(lc,l,mid,L,R);
	if(L>mid)return q2(rc,mid+1,r,L,R);
	return mg(q2(rc,mid+1,r,L,R),q2(lc,l,mid,L,R));
}
int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		p[0]=1;for(int i=1;i<=n;++i)p[i]=p[i-1]*bas%mod;
		bool ok=1;
		build(1,1,n);
		for(int i=1;i<=n;++i){
			int x;scanf("%d",&x);c(1,1,n,x);
			int l=min(x-1,n-x);
			if(l<=0)continue;
			if(ok&&q1(1,1,n,x-l,x-1).v!=q2(1,1,n,x+1,x+l).v){
				ok=0;puts("Y");
			}
		}
		if(ok)puts("N");
	}
	return 0;
}

标签:P2757,return,int,题解,mid,rc,tb,ta
来源: https://www.cnblogs.com/andy-lin102/p/16270627.html