题目大意

给一个1到N的排列\(A_i\),询问是否存在\(p_i\),\(i>=3\),使得\(A_{p_1}, A_{p_2}, ... ,A_{p_len}\)是一个等差序列。

题解

显然,我们只需要找到\(P_1, P_2, P_3\),使得其为等差数列即可。

考察等差数列的定义,不难得出:

\[2*P_2 = P_1 + P_3
\]

考察每一个\(P_2\),如果有\(P_2 - d\)已经出现,\(P_2 + d\)没有出现,那么一定可以组成等差序列。

我们考虑使用线段树维护每一个数字是否出现。如果一个数满足要求,以这个数开头的正序串和逆序串一定是不同的。我们维护每一个区间的哈希值,比较即可。

由于维护时满足区间查询,单点修改,所以我们使用线段树。

这个题WA了八次,最后找root要了数据才发现自己哈希的时候使用的pow数组用了int,结果溢出了orz

代码

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#define ll long long
#define mod 1000000007
#define p 3
using namespace std;
const int maxn = 10005;
struct seg {
int l, r;
ll hash1, hash2;
} t[maxn * 4];
int n, T;
ll pow[maxn];
void update(int k, ll m) {
ll tmp = m >> 1;
t[k].hash1 = ((t[k << 1].hash1 * pow[tmp]) % mod + t[k << 1 | 1].hash1) % mod;
t[k].hash2 =
((t[k << 1 | 1].hash2 * pow[m - tmp]) % mod + t[k << 1].hash2) % mod;
}
void add(int k, int pos) {
int l = t[k].l, r = t[k].r, mid = (l + r) >> 1;
if (l == r) {
t[k].hash1 = t[k].hash2 = 1;
return;
}
if (pos <= mid)
add(k << 1, pos);
else
add(k << 1 | 1, pos);
update(k, r - l + 1);
}
ll query(int k, int x, int y, int opt) {
if (x > y)
return 0;
int l = t[k].l, r = t[k].r, mid = (l + r) >> 1;
if (x <= l && r <= y) {
if (opt == 1)
return t[k].hash1;
else
return t[k].hash2;
}
if (y <= mid)
return query(k << 1, x, y, opt);
else if (x > mid)
return query(k << 1 | 1,x , y, opt);
else {
if (opt == 1) {
return ((query(k << 1, x, mid, 1) * pow[y - mid]) % mod+
query(k << 1 | 1, mid + 1, y, 1) % mod) %
mod;
} else
return ((query(k << 1, x, mid, 2) +
query(k << 1 | 1, mid + 1, y, 2) * pow[mid - x + 1])%mod) %
mod;
}
}
void build(int k, int l, int r) {
t[k].l = l, t[k].r = r;
if (l == r) {
t[k].hash1 = t[k].hash2 = 0;
return;
}
int mid = (l + r) >> 1;
build(k << 1, l, mid);
build(k << 1 | 1, mid + 1, r);
update(k, r - l + 1);
}
int main() {
//freopen("sequence.in", "r", stdin);
//freopen("sequence.out", "w", stdout);
scanf("%d", &T);
//pow[0] = 1;
pow[1] = p;
for (int i = 2; i <= 10001; i++)
pow[i] = (pow[i - 1] * p) % mod;
while (T--) {
scanf("%d", &n);
build(1, 1, n);
//memset(t, 0, sizeof(t));
int flag = 0;
int a[maxn];
memset(a, 0, sizeof(a));
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for (int i = 1; i <= n; i++) {
int x = a[i];
ll len = min(x - 1, n - x);
ll tmp1 = query(1, x - len, x - 1, 1);
ll tmp2 = query(1, x + 1, x + len, 2);
if (tmp1 != tmp2) {
flag = 1;
break;
}
add(1, x);
}
if (flag)
printf("Y\n");
else
printf("N\n");
}
}

[bzoj2124]等差子序列——线段树+字符串哈希的更多相关文章

  1. bzoj2124: 等差子序列线段树+hash

    bzoj2124: 等差子序列线段树+hash 链接 https://www.lydsy.com/JudgeOnline/problem.php?id=2124 思路 找大于3的等差数列其实就是找等于 ...

  2. BZOJ2124:等差子序列(线段树,hash)

    Description 给一个1到N的排列{Ai},询问是否存在1<=p1<p2<p3<p4<p5<…<pLen<=N (Len>=3), 使得A ...

  3. BZOJ2124 等差子序列(树状数组+哈希)

    容易想到一种暴力的做法:枚举中间的位置,设该位置权值为x,如果其两边存在权值关于x对称即合法. 问题是如何快速寻找这个东西是否存在.考虑仅将该位置左边出现的权值标1.那么若在值域上若关于x对称的两权值 ...

  4. [bzoj2124]等差子序列(hash+树状数组)

    我又来更博啦     2124: 等差子序列 Time Limit: 3 Sec  Memory Limit: 259 MBSubmit: 941  Solved: 348[Submit][Statu ...

  5. BZOJ 2124等差子序列 线段树&&hash

    [题目描述 Description] 给一个 1 到 N 的排列{Ai},询问是否存在 1<=p1<p2<p3<p4<p5<…<pLen<=N(Len& ...

  6. bzoj 2124 等差子序列 (线段树维护hash)

    2124: 等差子序列 Time Limit: 3 Sec  Memory Limit: 259 MBSubmit: 1922  Solved: 714[Submit][Status][Discuss ...

  7. BZOJ 2124: 等差子序列 线段树维护hash

    2124: 等差子序列 Description 给一个1到N的排列{Ai},询问是否存在1<=p1=3),使得Ap1,Ap2,Ap3,…ApLen是一个等差序列. Input 输入的第一行包含一 ...

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

    记录一下一个新学的线段树基础trick(真就小学生trick呗) 给你一个1到n的排列,你需要判断该排列内部是否存在一个3个元素的子序列(可以不连续),使得这个子序列是等差序列.\(n\) <= ...

  9. BZOJ2124: 等差子序列(树状数组&hash -> bitset 求是否存在长度为3的等差数列)

    2124: 等差子序列 Time Limit: 3 Sec  Memory Limit: 259 MBSubmit: 2354  Solved: 826[Submit][Status][Discuss ...

随机推荐

  1. jmeter对请求参数的签名处理

    1.首先在本地写好签名的算法,本文采用RSA签名. public final class Base64 { static private final int BASELENGTH = 128; sta ...

  2. 2.Linux文件和目录

    1. 目录和路径 linux下比较特殊的目录: . 代表此层目录 .. 代表上一层目录 - 代表前一个工作目录 ~ 代表『目前使用者身份』所在的home目录 ~account 代表 account 这 ...

  3. Linux编译安装opencv

    参考https://blog.csdn.net/huang826336127/article/details/78760885 一.下载opencv源码包 下载地址:https://opencv.or ...

  4. Python中enumerate函数用法详解

    enumerate函数用于遍历序列中的元素以及它们的下标,多用于在for循环中得到计数,enumerate参数为可遍历的变量,如 字符串,列表等 一般情况下对一个列表或数组既要遍历索引又要遍历元素时, ...

  5. 集显也能硬件编码:Intel SDK && 各种音视频编解码学习详解

    http://blog.sina.com.cn/s/blog_4155bb1d0100soq9.html INTEL MEDIA SDK是INTEL推出的基于其内建显示核心的编解码技术,我们在播放高清 ...

  6. js调用本地office打开服务器的office文件预览

    本来是想做成直接在网页上在线预览office文件的,但是找了好多,要不是收费,要不就是要调用别人的API不安全,所以纠结了好久还是用调用本地的office预览office文件. 废话不多说,那么怎么调 ...

  7. PokeCats开发者日志(三)

      现在是PokeCats游戏开发的第四天的晚上,明天要过周末了,所以提前写一下开发者日志吧! day4   day4主要是优化界面和增加游戏可玩性.   (1)感觉只有三只喵喵的话,玩家只需要无脑点 ...

  8. Java基础知识-去重

    java基础知识-去掉list集合中的重复元素: 思路: 首先新建一个容器resultList用来存放去重之后的元素 然后遍历sourceList集合中的元素 判断所遍历的元素是否已经存在于resul ...

  9. ArcGis下的叠加分析

     1矢量与矢量叠加的话就用ToolBox里有Overlay: 2如果是矢量和栅格叠加的话用Spatial analysis模块中的 zonal statistics: 3还有就是栅格与栅格的叠加S ...

  10. 使用XML传递数据

    HTML <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF- ...