T1:游戏体验

固定区间左端点,一边枚举区间右端点,一边计算把右端点加入当前区间后得到的区间总分数,时间复杂度为 \(O(m^2)\)。一个区间新加入一个数 \(x\) 要分 \(3\) 种情况:\(x\) 出现一次,区间总分数加上 \(x\) 对应的分数;\(x\) 出现两次,区间总分数减去 \(x\) 对应的分数;\(x\) 出现三次及三次以上就不需要再考虑了。

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;

inline void chmax(ll& x, ll y) { if (x < y) x = y; }

int main() {
    int n;
    cin >> n;
    vector<int> a(n);
    rep(i, n) cin >> a[i];
    
    int m;
    cin >> m;
    vector<int> x(m);
    rep(i, m) cin >> x[i], x[i]--;
    
    ll ans = 0;
    rep(l, m) {
        ll now = 0;
        vector<int> cnt(n);
        for (int r = l; r < m; ++r) {
            int i = x[r];
            cnt[i]++;
            if (cnt[i] == 1) now += a[i];
            else if (cnt[i] == 2) now -= a[i];
            chmax(ans, now);
        }
    }
    
    cout << ans << '\n';
    
    return 0;
}

f[i] 表示以 \(i\) 为左端点在当前时刻的区间的得分
pre[i] 表示和位置 \(i\) 相同的数,上一个位置是什么?

当加入新的数 \(x\) 时,从上一个和 \(x\) 相同的之后一个位置到当前位置的所有 f[i] 都增加 \(a_x\) 分;从当前位置往左数第 \(2\) 个和 \(x\) 相同的位置的之后一个位置到上一个和 \(x\) 相同的位置之间的所有 f[i] 都减少 \(a_x\) 分;从上一个和 \(x\) 相同的位置开始的左边的所有 f[i] 都加上 \(a_x\)

有区间查询和区间更新,所以可以用线段树来维护。但这里 \(m\)\(1e6\),会比较卡线段树,所以需要用zkw线段树。

T2:区间交集(三)

70 分做法:

link