zoukankan      html  css  js  c++  java
  • [BZOJ2124]等差子序列(hash)

    题意

    给出n个数的一个全排列(n<=1e5),询问是否存在三个数,使得这三个数成等差数列,多组询问

    思路

    枚举中间的数,显然在值域上两边的数成对称,那么如果存在等差数列,一定有一个比它小的数在左边,一个大的在右边,而且关于这个中间的数对称。换句话说,两个数的值如果关于该数对称,那么他们的位置就不能同时出现在该数的左边或者右边

    假设有5个数的全排列2 3 1 5 4,我们把在当前数左边设为1,右边设为0(当前数随便在左边或者右边)

    举个栗子:给定数列2 3 5 1 4

    依次加入每个数

    1.( 0 , 0, 0 , 0 , 0 )//初始状态

    2.( 0 , 1, 0 , 0 , 0)//加入2

    3.( 0 ,1 , 1 , 0 , 0 )//加入3,可以发现在原串中存在一个以3为中心的等差序列( 2 , 3 , 4)

    结合上面对左右关系的讨论,可以发现此时在第三步加入3后,以3为中心左右不对称,这就意味着左边有个比3小的数,右边有个比它大的数,所以存在等差序列

    于是原问题转化为求回文串,用hash同时维护对应顺着扫和逆着扫,查询就看对应的区间是否相等,不相等就说明有回文串

    单点修改怎么办?线段树维护hash就行啦

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define N 10005
    using namespace std;
    typedef unsigned long long ULL;
    const ULL base=1000000007;
    int T,n,a[N];
    ULL hash1[N<<2],hash2[N<<2],temp[N];
    
    template <class T>
    void read(T &x)
    {
    	char c;int sign=1;
    	while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    	while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign; 
    }
    void init()
    {
    	read(n);
    	for(int i=1;i<=n;++i) read(a[i]);
    	memset(hash1,0,sizeof(hash1));
    	memset(hash2,0,sizeof(hash2));
    }
    void modify(ULL *hash,int rt,int l,int r,int x,int val)
    {
    	if(l==r)
    	{
    		hash[rt]=val;
    		return;
    	}
    	int mid=(l+r)>>1;
    	if(x<=mid) modify(hash,rt<<1,l,mid,x,val);
    	else modify(hash,rt<<1|1,mid+1,r,x,val);
    	hash[rt]=hash[rt<<1]*temp[r-mid]+hash[rt<<1|1]; 
    }
    ULL query(ULL hash[],int rt,int l,int r,int x,int y)
    {
    	if(x<=l&&r<=y) return hash[rt];
    	int mid=(l+r)>>1;
    	if(y<=mid) return query(hash,rt<<1,l,mid,x,y);
    	if(x>mid) return query(hash,rt<<1|1,mid+1,r,x,y);
    	ULL h1=query(hash,rt<<1,l,mid,x,y),h2=query(hash,rt<<1|1,mid+1,r,x,y);
    	return h1*temp[min(r,y)-mid]+h2;//注意这里的min(r,y)-mid表示右边的size 
    }
    int main()
    {
    	read(T);
    	temp[0]=1;
    	for(int i=1;i<N;++i) temp[i]=temp[i-1]*base;
    	while(T--)
    	{
    		init();
    		for(int i=1;i<=n;++i)
    		{
    			int p=min(n-a[i],a[i]-1);
    			if(p&&query(hash1,1,1,n,a[i]-p,a[i]+p)!=query(hash2,1,1,n,(n-a[i]+1)-p,(n-a[i]+1)+p))
    			{
    				printf("Y
    ");
    				goto u;
    			}
    			modify(hash1,1,1,n,a[i],1);
    			modify(hash2,1,1,n,n-a[i]+1,1);
    		}
    		printf("N
    ");
    		u:;
    	}
    	return 0;
    }
    
  • 相关阅读:
    OpenCV在MFC图像控件内显示图像
    Android APK反编译具体解释(附图)
    Android下用Properties保存程序配置
    王灏:光音网络致力打造Wi-Fi大生态圈
    解决ccSvcHst.exe CPU占用超50%的问题,及其缘由
    配置管理工具比較
    应用程序无法正常启动0xc0150002 解决方式
    现有一些开源ESB总线的比較
    使用GridView自带分页的代码
    Hadoop 2.4.0新特性介绍
  • 原文地址:https://www.cnblogs.com/Chtholly/p/11194225.html
Copyright © 2011-2022 走看看