题解
记1:数组
每个位置的七种石头的前缀和为
。当
时,
。
记2:从第
人开始施法,直到第
人结束,中途不会出现七惜石不够的情况的区间为合法区间(不一定是闲暇区间),即
可知:如果一个区间
是 闲暇区间,则必然满足
,反之则不一定。
设
,即,所有以
为右边界的合法区间的左边界位置的集合
若
,显然增加一颗石头不会影响区间的合法性,所以 
若
,减少一颗
类型的石头会导致前面
的区间接下来失效,即
每次
时在
中找到
去更新答案即可
只需要使用任意一种能在
时间内增删查的数据结构维护即可
考虑更优的 (查):
如果
形如:
,那么
显然和
的差距仅为1。
我们将所有的
都提前计算并排序去重,可以利用7个双指针知道每种
会更新到的新
在数组的哪个位置,相当于做了离散化将
映射成
,用一个
的数组保存
的改变指向即可,每次可以
更新
所以查询的总复杂度降低到了
。(
最开始为
在排序后的
中的位置)
增:
在查的基础上用一个数组 min_left[] 记录
的最远左边界
删:
在增查的基础上维护一个vector<int> V[8][N],所以直接在
时,对
。可以证明即使
为负数越界到
也不会影响答案。
在
时,将
中记录的
所指向的最远左边界清零,然后清空
,最多不会清理超过7n次,所以总体复杂度为
。可以证明哪怕
又移动到被清理过的值,
后续再次清零它也不会影响答案。
#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; }