题解
记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;
}

查看11道真题和解析