题解

    记1:数组 a 每个位置的七种石头的前缀和为 pre_i [1 \leq i \leq n]。当 i = 0 时, pre_{(0, \thinspace \rm j)} = 0 \thinspace (1 \leq \rm j \leq 7) 。
    记2从第 L 人开始施法,直到第 R 人结束,中途不会出现七惜石不够的情况的区间为合法区间(不一定是闲暇区间),即 is\_legal(L, R) = 1
    可知:如果一个区间 [L, R] 是 闲暇区间,则必然满足 pre_{L-1} = pre_R,反之则不一定。
    设 S_i = \left\{ \rm j \thinspace \vert \thinspace is\_legal(\rm j, i) =1, 1 \leq \rm j \leq i \right\},即,所有以 i 为右边界的合法区间的左边界位置的集合
    若 a_{i+1} > 0显然增加一颗石头不会影响区间的合法性,所以 S_{i+1} = S_{i} \cup \{ i+1 \}
    若 a_{i+1} = - \rm t,减少一颗 \rm t 类型的石头会导致前面 pre_{(j-1, \thinspace t)} = pre_{(i, \thinspace t)} 的区间接下来失效,即 S_{i+1} = \{ \rm j \thinspace \vert \thinspace pre_{(j-1, \thinspace t)} \neq pre_{(i, \thinspace t)} , \thinspace j \in S_i \}
    每次 a_{i+1} = - \rm t 时在 S_i 中找到 min(\{j \thinspace \vert \thinspace pre_{j-1} = pre_i, \thinspace j \in S_i \}) 去更新答案即可
    只需要使用任意一种能在 O(logn) 时间内增删查的数据结构维护即可
    考虑更优的 (查)
    如果 pre_i 形如:\{ l_1, l_2, l_3, l_4, l_5, l_6, l_7 \} ,那么 pre_{i+1}显然和 pre_i 的差距仅为1。
    我们将所有的  pre_i 都提前计算并排序去重,可以利用7个双指针知道每种 pre_x 会更新到的新 pre_{x} 在数组的哪个位置,相当于做了离散化将 pre_{x} 映射成  pre\_pos ,用一个 2 \times 7 \times N 的数组保存 pre\_pos 的改变指向即可,每次可以O(1) 更新 pre\_pos 所以查询的总复杂度降低到了 O(n) 。( pre\_pos 最开始为 \{ 0, 0, 0, 0, 0, 0, 0 \} 在排序后的  pre  中的位置
    增:
    在查的基础上用一个数组 min_left[] 记录 pre\_pos 的最远左边界
    删:
    在增查的基础上维护一个vector<int> V[8][N],所以直接在 a_{i} > 0 时,对 \rm M[j][pre_{(i, j)}].push(pre\_pos) (1 \leq j \leq 7)。可以证明即使 pre_{(i, j)}为负数越界到 \rm M[j-1]也不会影响答案。
    在 a_{i} = -t< 0 时,将 \rm M[t][pre_{(i,t)}] 中记录的 pre\_pos 所指向的最远左边界清零,然后清空 \rm M[t][pre_{(i,t)}] ,最多不会清理超过7n次,所以总体复杂度为 O(n)。可以证明哪怕 pre\_pos 又移动到被清理过的值,\rm M 后续再次清零它也不会影响答案。
    
    
#include <bits/stdc++.h>



constexpr int N = 7e5 + 27;

using Seven = std::array<int, 7>;

int a[N], _left[N], _ed = 1;
Seven dt[2][N], *mp = dt[1];
std::vector<int> M[N];

signed main() {
    int n, maxl = 0, L, R;
    std::cin.tie(0)->sync_with_stdio(false);
    std::cin >> n;
    Seven cnt7{};
    for (int i = 1; i <= n; ++ i) {
        std::cin >> a[i];
        if (a[i] > 0) ++cnt7[a[i] - 1];
        else --cnt7[-a[i] - 1];
        mp[++_ed] = cnt7;
    }
    std::sort(mp + 1, mp + _ed + 1);
    _ed = std::unique(mp + 1, mp + _ed + 1) - mp - 1;
    L = std::find(mp + 1, mp + _ed + 1, Seven{}) - mp; // 找到原点
    Seven maxn{}, minn{}, cnt{};
    std::array<int, 8> store_pos{};
    for (int i = 1, r[7] = {1, 1, 1, 1, 1, 1, 1}; i <= _ed; ++ i) {
        Seven next;
        for (int j = 0; j < 7; ++ j) {
            maxn[j] = std::max(maxn[j], mp[i][j]);
            minn[j] = std::min(minn[j], mp[i][j]);
            ++ mp[i][j];
            while (r[j] < _ed && mp[r[j] + 1] <= mp[i]) ++ r[j];
            if (r[j] != i && mp[r[j]] == mp[i]) next[j] = r[j], dt[0][r[j]][j] = i;
            -- mp[i][j];
        }
        mp[i] = next;
    }
    for (int i = 0; i < 7; ++ i) {
        store_pos[i + 1] = (store_pos[i] += -minn[i]) + maxn[i] + 1;
    }
    for (int i = 1, r_now = L, ai = std::abs(a[i]) - 1; i <= n; ai = std::abs(a[++i]) - 1) {
        if (a[i] > 0) {
            for (int j = 0; j < 7; ++ j) {
                M[store_pos[j] + cnt[j]].push_back(r_now);
            }
            if (!_left[r_now]) _left[r_now] = i;
            ++cnt[ai], r_now = dt[1][r_now][ai];
        } else {
            auto &vec = M[store_pos[ai] + cnt[ai]];
            for (int i : vec) _left[i] = 0;
            vec.clear();
            --cnt[ai], r_now = dt[0][r_now][ai];
            if (_left[r_now] && i - _left[r_now] >= maxl) L = _left[r_now], R = i, maxl = R - L + 1;
        }
    }
    if (maxl) std::cout << L << ' ' << R << '\n';
    else std::cout << "QwQ\n";
    return 0 ^ 0;
}


    
全部评论

相关推荐

评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务