:::info[Description] Link. :::
:::infoSolution 题目中给出的操作可以看作是给 加正负号,考虑符号序列 ,则一个符号序列合法当且仅当任意后缀的符号和都在 范围内。因此考虑把 翻转,记 ,问题变为给 序列选择正负号要求任意前缀的符号和都在 范围内。
考虑一个暴力的 dp。设 表示当前考虑了前 个数,符号和为 时的最大答案。转移方程显然就是 ,最终答案就是 。时间复杂度为 难以通过。
考虑优化。注意到 奇偶性相同的时候 才存储了信息,因此考虑平移一下然后给所有位置重编号得到一个等价的转移式:,维护相邻项差分 容易发现差分序列是单调不增的,也就是 数组的 dp 信息是凸的。
考虑比较转移项 和 的大小,做差后可得 ,因此可以看作是前面斜率 的部分选择 ,后面斜率 的部分选择 。因此新函数的差分序列可以看作是在原有差分序列中插入一个 。因此直接用 multiset 维护整个序列的差分,然后支持二分查找和插入元素即可。时间复杂度被优化到 ,可以通过该题。
实现稍微有一点细节。 :::
:::success[Code]
namespace lowspeed_song {
inline void init() {
}
int a[N];
inline void sol() {
int n, m; cin >> n >> m;
for (int i = m; i; --i) cin >> a[i];
multiset<int, greater<>> se;
int f0 = 0;
for (int i = 1; i <= m; ++i) {
se.emplace(2 * a[i]), f0 -= a[i];
if (i & 1) f0 += *se.begin(), se.erase(se.begin());
int lim = (i & 1) ? (n + 1) / 2 : (n + 2) / 2;
while (se.size() >= lim) se.erase(--se.end());
} int res = f0, pre = f0;
for (const int &i : se) res = max(res, pre += i);
cout << res << '\n';
}
} // namespace lowspeed_song:::
难度:紫+
鲜活指数:6
喜欢的话,留下你的评论吧~