2024 CCPC 郑州 G - Same Sum

G - Same Sum

神秘题目,感觉是某一类典题。

考虑维护一个区间的怎么匹配,很显然是头尾匹配,否则会形成偏序关系导致大小不等。

题解很神秘的掏出了一个哈希函数

\[F_{+}(l, \, r) = \sum_{i = l}^r x^{a_i} \]

\[F_{-}(l, \, r) = \sum_{i = l}^r x^{-a_i} \]

其中 \(x\) 为任意哈希值,如果一个区间能够匹配,有 \(F_{+}(l, \, r) = x^{2m}F_{-}(l, \, r)\)\(m\) 为区间平均值。

这是直观的,就和回文串哈希相等类似,我们可以把区间平均值拍到 \(0\) 上,然后 \(F_{+}\) 就是 \(\Delta > 0\)\(F_{-}\) 就是 \(\Delta < 0\),拍到 \(0\) 上必然有正负匹配,那么转移回来就相当于两者差了两倍 \(\Delta\)

用双哈希可以草过此题,时间复杂度 \(O(n\log{n}\log{V})\)

参考代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<ll, ll> PII;
typedef pair<ll, PII> PPI;
const int N = 2e5 + 10, p1 = 1e9 + 7, p2 = 1e9 + 9;
const ll b1 = 131, b2 = 133;
int n, q, a[N];
struct Node {
    int l, r;
    ll sum, add;
}tr[N << 2], pos1[N << 2], neg1[N << 2], pos2[N << 2], neg2[N << 2];

ll add(ll a, ll b, ll mod) {
    if (!mod) return a + b;
    return (a + b < mod ? a + b : a + b - mod); 
}

ll ksm(ll a, ll k, ll mod) {
    ll res = 1;
    a %= mod;
    while (k) {
        if (k & 1) res = res * a % mod;
        k >>= 1;
        a = a * a % mod;
    }
    return res;
}

void pushup(int u) {
    tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
    pos1[u].sum = add(pos1[u << 1].sum, pos1[u << 1 | 1].sum, p1);
    pos2[u].sum = add(pos2[u << 1].sum, pos2[u << 1 | 1].sum, p2);
    neg1[u].sum = add(neg1[u << 1].sum, neg1[u << 1 | 1].sum, p1);
    neg2[u].sum = add(neg2[u << 1].sum, neg2[u << 1 | 1].sum, p2);
}

void pushdown(int u) {
    if (tr[u].add) {
        ll x = tr[u].add;
        tr[u].add = 0, tr[u << 1].add += x, tr[u << 1 | 1].add += x;
        tr[u << 1].sum += (tr[u << 1].r - tr[u << 1].l + 1) * x;
        tr[u << 1 | 1].sum += (tr[u << 1 | 1].r - tr[u << 1 | 1].l + 1) * x;
        ll pw1 = ksm(b1, x, p1), pw2 = ksm(b2, x, p2);
        ll inv1 = ksm(pw1, p1 - 2, p1), inv2 = ksm(pw2, p2 - 2, p2);
        (pos1[u << 1].sum *= pw1) %= p1, (pos1[u << 1 | 1].sum *= pw1) %= p1;
        (pos2[u << 1].sum *= pw2) %= p2, (pos2[u << 1 | 1].sum *= pw2) %= p2;
        (neg1[u << 1].sum *= inv1) %= p1, (neg1[u << 1 | 1].sum *= inv1) %= p1;
        (neg2[u << 1].sum *= inv2) %= p2, (neg2[u << 1 | 1].sum *= inv2) %= p2;
    }
}

void build(int u, int l, int r) {
    tr[u] = pos1[u] = pos2[u] = neg1[u] = neg2[u] = {l, r};
    if (l == r) {
        tr[u].sum = a[l];
        pos1[u].sum = ksm(b1, a[l], p1);
        pos2[u].sum = ksm(b2, a[l], p2);
        neg1[u].sum = ksm(pos1[u].sum, p1 - 2, p1);
        neg2[u].sum = ksm(pos2[u].sum, p2 - 2, p2);
        return;
    }
    int mid = l + r >> 1;
    build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
    pushup(u);
}

void modify(int u, int l, int r, ll x) {
    if (tr[u].l >= l && tr[u].r <= r) {
        tr[u].sum += (tr[u].r - tr[u].l + 1) * x, tr[u].add += x;
        ll pw1 = ksm(b1, x, p1), pw2 = ksm(b2, x, p2);
        ll inv1 = ksm(pw1, p1 - 2, p1), inv2 = ksm(pw2, p2 - 2, p2);
        (pos1[u].sum *= pw1) %= p1, (pos2[u].sum *= pw2) %= p2;
        (neg1[u].sum *= inv1) %= p1, (neg2[u].sum *= inv2) %= p2;
        return;
    }
    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    if (l <= mid) modify(u << 1, l, r, x);
    if (r > mid) modify(u << 1 | 1, l, r, x);
    pushup(u);
}

ll query_sum(Node *tr, int u, int l, int r, int mod) {
    if (tr[u].l >= l && tr[u].r <= r) return tr[u].sum;
    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    ll res = 0;
    if (l <= mid) res = query_sum(tr, u << 1, l, r, mod);
    if (r > mid) res = add(res, query_sum(tr, u << 1 | 1, l, r, mod), mod);
    return res;
}

string query(int l, int r) {
    ll sum = query_sum(tr, 1, l, r, 0);
    if (sum % (r - l + 1 >> 1)) return "NO";
    sum /= (r - l + 1 >> 1);
    if (query_sum(pos1, 1, l, r, p1) != query_sum(neg1, 1, l, r, p1) * ksm(b1, sum, p1) % p1) return "NO";
    if (query_sum(pos2, 1, l, r, p2) != query_sum(neg2, 1, l, r, p2) * ksm(b2, sum, p2) % p2) return "NO";
    return "YES";
}

void solve() {
    cin >> n >> q;
    for (int i = 1; i <= n; i ++ ) cin >> a[i];
    build(1, 1, n);
    for (int i = 1; i <= q; i ++ ) {
        int op, l, r, x;
        cin >> op >> l >> r;
        if (op == 1) cin >> x, modify(1, l, r, x);
        else cout << query(l, r) << "\n";
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int T = 1;
    // cin >> T;
    while (T -- ) solve();
    return 0;
}
posted @ 2025-04-06 21:38  YipChip  阅读(18)  评论(0)    收藏  举报