Loading

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

很有意思的题。

首先把等差数列的长度变为 \(3\),得到大幅简化。

然后考虑第一项和第三项值域上关于中间项对称。于是我们枚举中间项 \(a_i\),看看是否存在 \(a_i - k\) 在其左侧,\(a_i + k\) 在其右侧的情况。我们从左到右考虑每个 \(i\) 的话,就要求着 \(a_i - k\) 之前出现过而 \(a_i + k\) 没有出现过,因为如果 \(a_i + k\) 没有出现过就说明其在右侧。考虑刻画这个东西,出现过的数视为 \(1\),没出现过视为 \(0\),则要求存在 \(a_i - k\) 的位置是 \(1\)\(a_i + k\) 的位置是 \(0\),这就意味着将这个 \(01\) 串在处 \(a_i\) 翻折,会有一个位置有 \(1\) 也有 \(0\)。其实就是设 \(len = \min(a_i, n - a_i + 1)\),那么 \([a_i - len + 1, a_i + len - 1]\) 不是一个回文串。使用线段树维护哈希即可,时间复杂度的 \(\mathcal{O}(n \log n)\)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
// typedef __int128 i128;
typedef pair<int, int> pii;
const int N = 5e5 + 10, bas = 131;
template<typename T>
void dbg(const T &t) { cout << t << endl; }
template<typename Type, typename... Types>
void dbg(const Type& arg, const Types&... args) {
    cout << arg << ' ';
    dbg(args...);
}
namespace Loop1st {
int n, a[N];
ull pw[N];
struct Node {
    ull h1, h2;
    int len;
    Node operator + (const Node &A) const {
        return {h1 * pw[A.len] + A.h1, pw[len] * A.h2 + h2, len + A.len};
    }
} tr[N << 2];
struct SegTree {
    #define ls (u << 1)
    #define rs (u << 1 | 1)
    #define mid ((l + r) >> 1)
    void build(int l = 1, int r = n, int u = 1) {
        if (l == r) { tr[u].h1 = tr[u].h2 = 0; tr[u].len = 1; return ; }
        build(l, mid, ls); build(mid + 1, r, rs);
        tr[u] = tr[ls] + tr[rs];
    }
    void add(int x, int l = 1, int r = n, int u = 1) {
        if (l == r) { tr[u].h1 = tr[u].h2 = 1; return ; }
        if (x <= mid) add(x, l, mid, ls);
        else add(x, mid + 1, r, rs);
        tr[u] = tr[ls] + tr[rs];
    }
    Node ask(int x, int y, int l = 1, int r = n, int u = 1) {
        if (x <= l && r <= y) return tr[u];
        if (y <= mid) return ask(x, y, l, mid, ls);
        if (mid < x) return ask(x, y, mid + 1, r, rs);
        return ask(x, y, l, mid, ls) + ask(x, y, mid + 1, r, rs);
    }
} sgt;
void main() {
    cin >> n;
    pw[0] = 1;
    for (int i = 1; i <= n; i++) pw[i] = pw[i - 1] * bas;
    sgt.build(); 
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    for (int i = 1; i <= n; i++) {
        sgt.add(a[i]);
        int len = min(a[i], n - a[i] + 1);
        auto [h1, h2, _] = sgt.ask(a[i] - len + 1, a[i] + len - 1);
        if (h1 != h2) {
            cout << "Y\n";
            return ;
        }
    }
    cout << "N\n";
}

}
int main() {
    // freopen("data.in", "r", stdin);
    // freopen("data.out", "w", stdout);
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int T = 1;
    cin >> T;
    while (T--) Loop1st::main();
    return 0;
}
posted @ 2026-01-30 15:40  循环一号  阅读(0)  评论(0)    收藏  举报