• 【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} ot=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;
    }
    
  • 相关阅读:
    FLASH开发[00]
    slickedit使用小技巧
    网络编程[34]
    网络编程[39]
    网络编程[41]
    网络编程[37]
    网络编程[32]
    网络编程[35]
    Apache安装和配置
    网络编程[40]
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF452F.html
Copyright © 2020-2023  润新知