CF452F等差子序列 & 线段树+hash查询区间是否为回文串
记录一下一个新学的线段树基础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\) 暴力判一遍
于是你就得到了一个 \(n^2\) 的暴力
大概长这样
//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;
}
CF452F等差子序列 & 线段树+hash查询区间是否为回文串的更多相关文章
- bzoj2124: 等差子序列线段树+hash
bzoj2124: 等差子序列线段树+hash 链接 https://www.lydsy.com/JudgeOnline/problem.php?id=2124 思路 找大于3的等差数列其实就是找等于 ...
- BZOJ 2124等差子序列 线段树&&hash
[题目描述 Description] 给一个 1 到 N 的排列{Ai},询问是否存在 1<=p1<p2<p3<p4<p5<…<pLen<=N(Len& ...
- BZOJ2124:等差子序列(线段树,hash)
Description 给一个1到N的排列{Ai},询问是否存在1<=p1<p2<p3<p4<p5<…<pLen<=N (Len>=3), 使得A ...
- 牛客练习赛64 如果我让你查回文你还爱我吗 线段树 树状数组 manacher 计数 区间本质不同回文串个数
LINK:如果我让你查回文你还爱我吗 了解到了这个模板题. 果然我不会写2333... 考试的时候想到了一个非常辣鸡的 线段树合并+莫队的做法 过不了不再赘述. 当然也想到了manacher不过不太会 ...
- HDU 4632 Palindrome subsequence(区间dp,回文串,字符处理)
题目 参考自博客:http://blog.csdn.net/u011498819/article/details/38356675 题意:查找这样的子回文字符串(未必连续,但是有从左向右的顺序)个数. ...
- HDU - 5157 :Harry and magic string (回文树,求多少对不相交的回文串)
Sample Input aca aaaa Sample Output 3 15 题意: 多组输入,每次给定字符串S(|S|<1e5),求多少对不相交的回文串. 思路:可以用回文树求出以每个位置 ...
- bzoj 2124 等差子序列 (线段树维护hash)
2124: 等差子序列 Time Limit: 3 Sec Memory Limit: 259 MBSubmit: 1922 Solved: 714[Submit][Status][Discuss ...
- BZOJ 2124: 等差子序列 线段树维护hash
2124: 等差子序列 Description 给一个1到N的排列{Ai},询问是否存在1<=p1=3),使得Ap1,Ap2,Ap3,…ApLen是一个等差序列. Input 输入的第一行包含一 ...
- [bzoj2124]等差子序列——线段树+字符串哈希
题目大意 给一个1到N的排列\(A_i\),询问是否存在\(p_i\),\(i>=3\),使得\(A_{p_1}, A_{p_2}, ... ,A_{p_len}\)是一个等差序列. 题解 显然 ...
随机推荐
- Codeforces Round #585 (Div. 2) E. Marbles (状压DP),BZOJ大理石(同一道题)题解
题意 林老师是一位大理石收藏家,他在家里收藏了n块各种颜色的大理石,第i块大理石的颜色为ai.但是林老师觉得这些石头在家里随意摆放太过凌乱,他希望把所有颜色相同的石头放在一起.换句话说,林老师需要对现 ...
- 【java】学习路径39-Buffered缓冲输出流
import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOException; pu ...
- 给ShardingSphere提了个PR,不知道是不是嫌弃我
说来惭愧,干了 10 来年程序员,还没有给开源做过任何贡献,以前只知道嘎嘎写,出了问题嘎嘎改,从来没想过提个 PR 去修复他,最近碰到个问题,发现挺简单的,就随手提了个 PR 过去. 问题 问题挺简单 ...
- 第七章 完成kubernetes集群部署并验证
在其中一运算个节点上操作就行 创建nginx资源配置清单的yaml文件 [root@hdss7-21 ~]# vim /opt/kubernetes/conf/nginx-ds.yaml apiVer ...
- 《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(19)-Fiddler精选插件扩展安装,将你的Fiddler武装到牙齿
1.简介 Fiddler本身的功能其实也已经很强大了,但是Fiddler官方还有很多其他扩展插件功能,可以更好地辅助Fiddler去帮助用户去开发.测试和管理项目上的任务.Fiddler已有的功能已经 ...
- 华南理工大学 Python第7章课后小测-2
1.(单选)以下选项中使Python脚本程序转变为可执行程序的第三方库的是(本题分数:3)A) NetworkxB) pyinstallC) RequestsD) PyPDF2您的答案:B 正确率: ...
- Python 第二次实验
[1] (程序设计)三位水仙花数的计算."三位水仙花数"是指一个三位整数,其各位数字的3次方和等于该数本身.例如:ABC是一个"3位水仙花数",则:A的3次方+ ...
- 思维导图学《On Java》基础卷 + 进阶卷
说明 目录 思维导图 导读 第 1 章 什么是对象 第 3 章 一切都是对象 第 6 章 初始化和清理 第 7 章 实现隐藏 第 8 章 复用 第 9 章 多态 第 10 章 接口 第 11 章 内部 ...
- 使用containerlab搭建cilium BGP环境解析
使用 Containerlab + Kind 快速部署 Cilium BGP 环境一文中使用Containerlab和Cilium实现了模拟环境下的Cilium BGP网络.它使用Containerl ...
- 在Ubuntu上安装Odoo时遇到的问题
这两天开始看<Odoo快速入门与实践 Python开发ERP指南>(刘金亮 2019年5月第1版 机械工业出版社).试着在Ubuntu上安装Odoo,遇到很多问题,通过在网上查找,都已解 ...