ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

终焉之排列

2021-10-14 22:03:28  阅读:148  来源: 互联网

标签:排列 相同 int len 终焉 哈希 出现 rightarrow


终焉之排列

题意:

给定一个序列 \(a\),求有没有点对满足 \(x\leq y \leq z\) ,有 \(a_x+a_z=2a_y\)

分析:

暴力写法当然是记录每个值出现的位置,然后对于每一个 \(a_i\) 向两边进行搜索。

但是 暴力是一种虫豸的写法 ,考虑正解。

我们设 \(h[x]=1/0\) 表示 \(x\) 是否在 \([1,j]\) 中出现/没出现。

取 \(len=min(n-x,x-1)\) ,如果 \(h[x-len \rightarrow x-1]=h[x+len \rightarrow x+1]\) 不相同,则证明有这样的点对。

可能理解起来有点抽象,我们取一组样例:

1 5 2 4 3
  • 当进行到第 \(3\) 次循环时,\(h[1 \rightarrow n]\) 可以表示为:
1 1 0 0 1

此时 \(a[i]=2\) ,则 \(len=min(5-2,2-1)=1\) ,则判断 \(h[1]\) 和 \(h[3]\) 是否相同。

不相同,此时的意义是: \(1\) 在 \(2\) 之前出现过,\(3\) 在 \(2\) 之前没出现过,因此 \(2\) 肯定在 \(1,3\) 之间。

  • 当进行到第 \(4\) 次循环,\(h[1 \rightarrow n]\) 可以表示为:
1 1 0 1 1

此时 \(a[i]=4\) ,则 \(len=1\) ,判断 \(h[5]\) 和 \(h[3]\) 是否相同:

不相同,此时的意义是 \(5\) 在 \(4\) 之前出现过,\(3\) 在 \(5\) 之前没出现过,因此 \(4\) 肯定在 \(3,5\) 之间。

可以看出,我们每次都这么算一遍,时间复杂度太炸了,因此需要一种数据结构,能够存储这个 \(0/1\) 串。

考虑字符串哈希:每个长度代表一个值,用线段树维护 \([l,r]\) 区间内 哈希值 的正值/反值,用两个数组维护。

判断 区间 \([x-len,x-1]\) 的正哈希值和 \([x+1,x+len]\) 的反哈希值是否相同,也就是区间 \(h[x-len,x-1]\) 和 \(h[x+len,x+1]\) 是否相同。

如果相同,就证明不在中间,否则在中间,输出 \(YES\) 即可。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5,P=71;
int sum[2][N<<2],a[N],p[N];
int n,m,T;

void modify(int op,int x,int l,int r,int pos){
    if(l==r){
        sum[op][x]=1; return;
    }
    int mid=l+r>>1;
    if(pos<=mid) modify(op,x<<1,l,mid,pos);
    else         modify(op,x<<1|1,mid+1,r,pos);
    if(op==0) sum[op][x]=sum[op][x<<1]+sum[op][x<<1|1]*p[mid-l+1];
    else      sum[op][x]=sum[op][x<<1|1]+sum[op][x<<1]*p[r-mid];
}

int query(int op,int x,int l,int r,int L,int R){
    if(L<=l&&r<=R){
        if(op==0) return p[l-L]*sum[op][x];
        else return      p[R-r]*sum[op][x];
    }
    int mid=l+r>>1,res=0;
    if(L<=mid) res+=query(op,x<<1,l,mid,L,R);
    if(R>mid)  res+=query(op,x<<1|1,mid+1,r,L,R);
    return res;
}

int main(){
    cin>>T;
    while(T--){
        cin>>n;  int flag=0;
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        p[0]=1; for(int i=1;i<=n;i++) p[i]=p[i-1]*P;
        memset(sum,0,sizeof(sum));
        for(int i=1;i<n-1;i++){
            modify(0,1,1,n,a[i]); modify(1,1,1,n,a[i]);
            int len=min(n-a[i+1],a[i+1]-1);
            if(len==0) continue;
            int Front=query(0,1,1,n,a[i+1]-len,a[i+1]-1);
            int  Back=query(1,1,1,n,a[i+1]+1,a[i+1]+len);
            if(Front!=Back){
                puts("YES"); flag=1; break;
            } 
        }
        if(flag==0) puts("NO");
    }
    system("pause");
    return 0;
}

标签:排列,相同,int,len,终焉,哈希,出现,rightarrow
来源: https://www.cnblogs.com/guanlexiangfan/p/15408659.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有