第九届河北省大学生程序设计竞赛 L.通信拦截

难蚌,我以为签到呢,结果出题人说是次难题,当时 VP 看这题估计不过半小时就把这题做出来了。

不知道题解巴拉巴拉说什么线段树什么的,显然这题不需要这么高级的算法。

注意到 \(x\) 对一个线段 \([l, \, r]\) 的贡献,在前半段可以发现是一个等差数列加上一个全部相等的一段,贡献为

\[\frac{(x - l)(x - l + 1)}{2} + (r - (2l - x))(l - x) = \frac{-3x^2 + (2r + 4l + 1)x - l(2r + l + 1)}{2} \]

在右半段也有个类似的贡献,是等差数列取不完的贡献

\[\frac{x^2 - (2r + 1)x + r(r + 1)}{2} \]

然后放两个堆出来维护一下左区间和右区间的贡献,我们就可以知道总贡献。

时间复杂度 \(O(n\log{n})\)

#include "bits/stdc++.h"
using namespace std;

typedef long long ll;
typedef pair<ll, ll> PII;
const int N = 2e5 + 10;

int n;
struct Segment {
    ll l, r;
}a[N];

bool cmp(Segment x, Segment y) {
    if (x.l == y.l) return x.r < y.r;
    return x.l < y.l;
}

ll calcL1(int x) {return 2 * a[x].r + 4 * a[x].l + 1;}
ll calcL2(int x) {return -a[x].l * (2 * a[x].r + a[x].l + 1);}
ll calcR1(int x) {return -(2 * a[x].r + 1);}
ll calcR2(int x) {return a[x].r * (a[x].r + 1);}

void solve() {
    cin >> n;
    for (int i = 1; i <= n; i ++ ) {
        int x; cin >> x;
        a[i] = {i, min(i + x, n)};
    }
    sort(a + 1, a + n + 1, cmp);
    int cnt = 1;
    ll Lc1 = 0, Lc2 = 0, Rc1 = 0, Rc2 = 0;
    priority_queue<PII, vector<PII>, greater<PII>> Lseg, Rseg;
    for (ll i = 1; i <= n; i ++ ) {
        while (cnt <= n && a[cnt].l == i) {
            Lseg.push({a[cnt].l + a[cnt].r >> 1, cnt});
            Lc1 += calcL1(cnt);
            Lc2 += calcL2(cnt);
            cnt ++ ;
        }
        while (Lseg.size() && Lseg.top().first < i) {
            int id = Lseg.top().second; Lseg.pop();
            Rseg.push({a[id].r, id});
            Lc1 -= calcL1(id);
            Lc2 -= calcL2(id);
            Rc1 += calcR1(id);
            Rc2 += calcR2(id);
        }
        while (Rseg.size() && Rseg.top().first < i) {
            int id = Rseg.top().second; Rseg.pop();
            Rc1 -= calcR1(id);
            Rc2 -= calcR2(id);
        }
        cout << (-3 * i * i * (ll)Lseg.size() + Lc1 * i + Lc2) / 2 + (i * i * (ll)Rseg.size() + Rc1 * i + Rc2) / 2 << "\n";
    }
}

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