把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【CF452F】Permutation(线段树维护哈希值)

点此看题面

大致题意: 给定一个\(n\)的排列,问是否存在\(i<j<k\)满足\(p_j=\frac{p_i+p_k}2\)

转化

注意到这是一个排列。

不妨设\(q_x\)表示数\(x\)所在的位置,问题就变成是否存在\(x,t\)满足\(q_{x-t}<q_x<q_{x+t}\)\(q_{x-t}>q_x>q_{x+t}\)

如果我们按照\(q_x\)从小到大枚举\(x\)(即按\(i\)从小到大枚举\(x=p_i\)),把其余的\(q\)根据与\(q_x\)的大小关系修改为\(0/1\),则问题就变成对于每个\(x\)是否存在\(t\)满足\(q_{x-t}\not=q_{x+t}\)

那么对于\(x\)若不存在一个合法的\(t\),相当于从\(x\)出发两侧的字符完全相等。

只要把\(q\)中的信息哈希起来用线段树维护,就可以快速比较了。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 300000
using namespace std;
int n,p[N+5];
struct Hash//哈希
{
	#define ull unsigned long long
	#define CU Con ull&
	ull x,y;I Hash() {x=y=0;}I Hash(CU a) {x=y=a;}I Hash(CU a,CU b):x(a),y(b){}
	I Hash operator + (Con Hash& o) Con {return Hash(x+o.x,y+o.y);}
	I Hash operator - (Con Hash& o) Con {return Hash(x-o.x,y-o.y);}
	I Hash operator * (Con Hash& o) Con {return Hash(x*o.x,y*o.y);}
	I bool operator != (Con Hash& o) Con {return x^o.x||y^o.y;}
}seed(19,302627441),P[N+5];
class SegmentTree//线段树维护哈希值
{
	private:
		#define PT CI l=1,CI r=n,CI rt=1
		#define LT l,mid,rt<<1
		#define RT mid+1,r,rt<<1|1
		#define PU(x) (A[x]=A[x<<1]*P[r-mid]+A[x<<1|1],B[x]=B[x<<1]+B[x<<1|1]*P[mid-l+1])
		Hash A[N<<2],B[N<<2];
	public:
		I void U(CI x,PT)//单点修改
		{
			if(l==r) return (void)(A[rt]=B[rt]=1);RI mid=l+r>>1;
			x<=mid?U(x,LT):U(x,RT),PU(rt);
		}
		I Hash QA(CI L,CI R,PT)//正着
		{
			if(L==l&&r==R) return A[rt];RI mid=l+r>>1;if(R<=mid) return QA(L,R,LT);
			if(L>mid) return QA(L,R,RT);return QA(L,mid,LT)*P[R-mid]+QA(mid+1,R,RT);
		}
		I Hash QB(CI L,CI R,PT)//倒着
		{
			if(L==l&&r==R) return B[rt];RI mid=l+r>>1;if(R<=mid) return QB(L,R,LT);
			if(L>mid) return QB(L,R,RT);return QB(L,mid,LT)+QB(mid+1,R,RT)*P[mid-L+1];
		}
}S;
int main()
{
	RI i;for(scanf("%d",&n),P[0]=i=1;i<=n;++i) scanf("%d",p+i),P[i]=P[i-1]*seed;//读入同时,预处理哈希种子的幂
	RI t;for(i=1;i<=n;S.U(p[i]),++i) if(t=min(p[i]-1,n-p[i]))//枚举数
		if(S.QA(p[i]-t,p[i]-1)!=S.QB(p[i]+1,p[i]+t)) return puts("YES");//判断两侧01是否相同
	return puts("NO"),0;
}
posted @ 2020-08-17 13:25  TheLostWeak  阅读(166)  评论(0编辑  收藏  举报