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}\)是一个等差序列. 题解 显然 ...
随机推荐
- Matery主题添加Pjax
如何给matery主题添加Pjax? Pjax优点 1.减轻服务端压力 2.按需请求,每次只需加载页面的部分内容,而不用重复加载一些公共的资源文件和不变的页面结构,大大减小了数据请求量,以减轻对服务器 ...
- github action 实现CI/CD
两种github action 打包.Net Core 项目docker镜像推送到阿里云镜像仓库 1.GitHub Actions 是什么? 大家知道,持续集成由很多操作组成,比如抓取代码.运行测试. ...
- 第四十篇:Vue的生命周期(一)
好家伙,军训结束了,回归 Vue实例的生命周期 1.什么是生命周期? 从Vue实例创建,运行到销毁期间总是伴随着各种各样的事件,这些事件,统称为生命周期. 2.什么是生命周期钩子? 生命周期函数的别称 ...
- docker可视化
可视化第一种方式 Portainer(不是最佳选择但先用这个) docker run -d -p 8088:9000 \ #docker run 启动:通过内网9000端口,外网8088端口:rest ...
- Mac_linux_ssh防掉线
vi ~/.ssh/config 加入一条 ServerAliveInterval 60 #客户端主动向服务端请求响应的间隔
- 【Android 逆向】ARM switch 逆向
#include <stdio.h> int switch1(int a, int b, int i){ switch (i){ case 1: return a + b; break; ...
- 硬核剖析Redis单线程为什么那么快?
(本文首发于"数据库架构师"公号,订阅"数据库架构师"公号,一起学习数据库技术,助力职业发展) Redis目前是使用率最高的内存库数据库,是企业应用开发的必备, ...
- 采云端&采云链:从订单协同到采购供应链,让采购供应链互联互通
采购供应链安全从来没有像现在这样显得如此重要和紧迫,也从来没有像现在这样复杂和敏感,对企业的经营产生决定性的影响.尤其在疫情期间,采购供应链更加牵一发而动全身,成为"运筹帷幄,决胜于千里之外 ...
- OKR之剑(理念篇)01—— OKR带给我们的改变
作者:vivo互联网平台产品研发团队 一.前言 OKR即目标与关键成果法,起源于英特尔,在谷歌发扬光大.近几年在国内比较火,很多企业都相继引入了OKR的管理方式,小到2-3人的小微初创公司,大到十几万 ...
- P1829 [国家集训队]Crash的数字表格
P1829 [国家集训队]Crash的数字表格 原题传送门 前置芝士 莫比乌斯反演 乘法逆元 数论分块 正文 //补充:以下式子中的除法均为整除 由题目可以得知,这道题让我们所求的数,用一个式子来表达 ...