当前位置: 首页 > news >正文

P2757 [国家集训队] 等差子序列 题解

Link

好题。考虑简化题意:找一个 \(|p| \geq 3\) 的序列 \(p\) 使得 \(A_{p_i}\) 呈现等差数列,那我们找一个三个数的等差数列就可以了。中间值是特殊的,我们枚举中间值,判断左右两边是否存在一个公差相等的等差数列项。

用到一个有用的 \(01\) 序列转换 Trick。我们从左到右遍历 \(A\),同时维护出一个 \(01\)\(b\),每次扫描到 \(A_i\) 就将 \(b\) 中对应的 \(i\) 位设置成 \(1\)。考虑一组等差数列存在且公差为 \(k\),这意味着 \(A_i - k, A_i + k \in [1, n]\) 同时前一项出现了,后一项尚未出现,即 \(b_{A_i - k} = 1\)\(b_{A_i + k} = 0\),此时 \(A_i - k, A_i, A_i + k\) 顺序排列形成公差为 \(k\) 的长度为 \(3\) 的等差数列。

现在的问题是怎么维护或者说高效判断出有存在于左右两边的符合公差要求的项。我们再次转化问题为检查 \(b\) 是否关于 \(A_i\) 呈现中心对称。如果以 \(A_i\) 为中心的对称区间不是回文,则存在某个 \(k\) 使得 \(A_i - k\)\(A_i + k\) 一个在左一个在右,反之如果是回文的,意味着对于每个 \(k\)\(A_i - k, A_i + k\) 要么都出现要么都不出现。

现在新的问题是如何快速判断回文串?常规的,使用字符串哈希。维护一棵线段树支持带修查询的字符串哈希值,对于 \(A_i\),我们计算正序哈希 \(H_{[A_i - k, A_i - 1]}\) 和逆序哈希 \(H'_{[A_i + 1, A_i + k]}\),如果 \(H = H'\) 则存在回文。实现上,注意逆序哈希的线段树合并顺序。

#include <bits/stdc++.h>using i64 = long long;
using u64 = unsigned long long;constexpr int N = 6e5 + 7;
constexpr u64 B = 13331;int n;
int a[N];
u64 b[N];struct SegTree {struct node {int l, r;u64 v1, v2;} tr[N << 2];#define ls(o) (o << 1)#define rs(o) (o << 1 | 1)void pushup(const int o) {int len_r = tr[rs(o)].r - tr[rs(o)].l + 1;int len_l = tr[ls(o)].r - tr[ls(o)].l + 1;tr[o].v1 = tr[ls(o)].v1 * b[len_r] + tr[rs(o)].v1;tr[o].v2 = tr[rs(o)].v2 * b[len_l] + tr[ls(o)].v2;}void build(int o, int l, int r) {tr[o].l = l, tr[o].r = r; tr[o].v1 = tr[o].v2 = 0;if (l == r) {return;}int mid = (l + r) >> 1;build(ls(o), l, mid);build(rs(o), mid + 1, r);}void update(int o, int l, int r, int p) {if (l == r) {tr[o].v1 = tr[o].v2 = 1;return;}int mid = (l + r) >> 1;if (p <= mid)update(ls(o), l, mid, p);elseupdate(rs(o), mid + 1, r, p);pushup(o);}u64 query1(int o, int l, int r, int ql, int qr) {if (ql <= l && r <= qr) {return tr[o].v1 * b[qr - r];}int mid = (l + r) >> 1;u64 res = 0;if (ql <= mid)res += query1(ls(o), l, mid, ql, qr);if (qr > mid)res += query1(rs(o), mid + 1, r, ql, qr);return res;}u64 query2(int o, int l, int r, int ql, int qr) {if (ql <= l && r <= qr) {return tr[o].v2 * b[l - ql];}int mid = (l + r) >> 1;u64 res = 0;if (qr > mid)res += query2(rs(o), mid + 1, r, ql, qr);if (ql <= mid)res += query2(ls(o), l, mid, ql, qr);return res;}
} seg;void init() {b[0] = 1;for (int i = 1; i < N; i++) {b[i] = b[i - 1] * B;}
}void solve() {std::cin >> n;for (int i = 1; i <= n; i++) {std::cin >> a[i];}seg.build(1, 1, n);for (int i = 1; i <= n; i++) {int t = a[i]; int len = std::min(t - 1, n - t);if (len > 0) {u64 h1 = seg.query1(1, 1, n, t - len, t - 1);u64 h2 = seg.query2(1, 1, n, t + 1, t + len);if (h1 != h2) {std::cout << "Y\n";return;}}seg.update(1, 1, n, t);}std::cout << "N\n";
}int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);int t;std::cin >> t;init();while (t--) {solve();}return 0;
}
http://www.jsqmd.com/news/30457/

相关文章:

  • 拾壹月Ⅲ
  • 20251103周一日记
  • Window 安装多个 MySQL 实例 - Higurashi
  • 普赛斯
  • claude code+openspec开发java代码基本流程
  • 【C】结构体赋值
  • Office 2024 专业增强版下载安装教程:安装/下载/激活/全流程教程
  • Office 2024 专业增强版下载安装教程:安装/下载/激活/全流程教程
  • 模拟赛 29
  • 11.3阅读笔记
  • fhq treap笔记
  • K8S最全详解 - 智慧园区
  • 11/3
  • ICPC2025 武汉站 游记
  • 25.11.03
  • win10安装neo4j-community-3.5.7-windows
  • 工作感受月记(202511月)
  • 基于Blocking queue的生产消费模型
  • React中useContext的基本使用和原理解析
  • JDK的安装过程
  • 阅读笔记0
  • File文件操作
  • 越南航空数据泄露事件深度解析
  • P11261 [COTS 2018] 直方图 Histogram
  • 2025csp-j游记(废物版)
  • leetcode55. 跳跃游戏 45. 跳跃游戏 II
  • 个体户办理食品经营须知
  • redux-thunk和createAsyncThunk
  • 2025.11.3——1绿1蓝
  • Next.js路由段配置选项笔记