ICode9

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

CF452F等差子序列 & 线段树+hash查询区间是否为回文串

2021-11-10 14:00:39  阅读:152  来源: 互联网

标签:cnt ch hash int head CF452F 差子 define


记录一下一个新学的线段树基础trick(真就小学生trick呗)

给你一个1到n的排列,你需要判断该排列内部是否存在一个3个元素的子序列(可以不连续),使得这个子序列是等差序列。n<=3e5

考虑等差数列的相关性质,对于一个3个数的等差数列,当 a[i] 作为中间项可行时,当且仅当一定存在至少1个 k,使得 a[i] - k 这个元素在它的左边,a[i] + k 这个元素在它的右边 (为了方便,这里的k可以是负数)

那我们在顺序枚举 a[i] 的过程中,不妨把用过的 a[i] 标记成1,没用过的标记成零,然后对于所有范围内的 k 暴力判一遍

于是你就得到了一个 n2 的暴力

大概长这样

//Talking to the moon
#include <bits/stdc++.h>
#define N 1000010
#define M 2000010
#define int long long
#define int_edge int to[M],val[M],nxt[M],head[N],cnt=0;
using namespace std;
int used[10010],a[10010];
//void add_edge(int x,int y ){to[++cnt]=y;nxt[cnt]=head[x];head[x]=cnt;}
int read(){
	int fu=1,ret=0;char ch;
	for(;!isdigit(ch);ch=getchar())if(ch=='-')fu*=-1;
	for(;isdigit(ch);ch=getchar())ret=(ret<<1)+(ret<<3)+ch-'0';
	return ret*fu;
}
signed main()
{
	int n=read(),ans=0;
	for(int i=1;i<=n;i++)a[i]=read();
	for(int i=1;i<=n;i++)
	{
		for(int j=1;a[i]-j>=1&&a[i]+j<=n;j++)
			if(used[a[i]-j]!=used[a[i]+j]){ans=1;break;}
		if(ans==1)break;
		used[a[i]]=1;
	}
	if(ans==1)puts("YES");
		else puts("NO");
	return 0;
}

接下来是正解部分

我们发现正向考虑枚举 k 好像没有什么优化空间,而且题目也没让我们找 k ,那么正难则反,我们可以考虑作为中间项不可行的情况,即不存在k使得 a[i] + k 和 a[i] - k 的标记相同

那不就是回文串

于是我们的问题就变成了在值域上搞单点修改加区间判断是否回文

先不考虑修改,判断回文串其实是有一个非常优秀的朴素Hash算法的

就是考虑正反向各Hash一遍,然后判断查询区间的正反Hash值是否相等即可

然后Hash值是可以加减的

也就是说你把a在第1位的hash值加上b在第2位的hash值加起来就可以得到ab的hash值

那么修改就简单了,我们可以把这个Hash移到一棵线段树上(树状数组也可)

每个叶子节点存的是单点hash后的值

然后就可以支持单点修改,区间查询了

需要注意的是合并的时候需要把每一位乘上这一位对应的hash底数(比如131的多少次方什么的)

查询的时候也是

//Talking to the moon
#include <bits/stdc++.h>
#define N 300010
#define M 2000010
#define int unsigned long long
#define int_edge int to[M],val[M],nxt[M],head[N],cnt=0;
using namespace std;
int a[N],h[N];
//void add_edge(int x,int y ){to[++cnt]=y;nxt[cnt]=head[x];head[x]=cnt;}
int read(){
	int fu=1,ret=0;char ch;
	for(;!isdigit(ch);ch=getchar())if(ch=='-')fu*=-1;
	for(;isdigit(ch);ch=getchar())ret=(ret<<1)+(ret<<3)+ch-'0';
	return ret*fu;
}
int ls(int x){return x*2;}
int rs(int x){return x*2+1;}
struct Seg1{
	int tr[N*4];
	void update(int nw,int l,int r,int x){
		if(l==r){
			tr[nw]++;
			return;
		}
		int mid=(l+r)/2;
		if(x<=mid)update(ls(nw),l,mid,x);
			else update(rs(nw),mid+1,r,x);
		tr[nw]=tr[ls(nw)]*h[r-mid]+tr[rs(nw)];
	}
	int query(int nw,int l,int r,int x,int y){
		if(x<=l&&r<=y){
			return tr[nw]*h[y-r];
		}
		int mid=(l+r)/2,sum=0;
		if(x<=mid)sum+=query(ls(nw),l,mid,x,y);
		if(y>mid)sum+=query(rs(nw),mid+1,r,x,y);
		return sum;
	}
}S1;
struct Seg2{
	int tr[N*4];
	void update(int nw,int l,int r,int x){
		if(l==r){
			tr[nw]++;
			return;
		}
		int mid=(l+r)/2;
		if(x<=mid)update(ls(nw),l,mid,x);
			else update(rs(nw),mid+1,r,x);
		tr[nw]=tr[rs(nw)]*h[mid-l+1]+tr[ls(nw)];
	}
	int query(int nw,int l,int r,int x,int y){
		if(x<=l&&r<=y){
			return tr[nw]*h[l-x];
		}
		int mid=(l+r)/2,sum=0;
		if(x<=mid)sum+=query(ls(nw),l,mid,x,y);
		if(y>mid)sum+=query(rs(nw),mid+1,r,x,y);
		return sum;
	}
}S2;

signed main()
{
	int n=read(),ans=0;
	h[0]=1;for(int i=1;i<=n;i++)h[i]=h[i-1]*131;
	for(int i=1;i<=n;i++)
	{
		a[i]=read();
		int num=min(a[i]-1,n-a[i]),l=a[i]-num,r=a[i]+num;
		if(S1.query(1,1,n,l,r)!=S2.query(1,1,n,l,r)){ans=1;break;}
		S1.update(1,1,n,a[i]);S2.update(1,1,n,a[i]);
	}	
	if(ans)puts("YES");
		else puts("NO");
	return 0;
}

标签:cnt,ch,hash,int,head,CF452F,差子,define
来源: https://www.cnblogs.com/shight/p/15533243.html

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

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

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

ICode9版权所有