题解 P10144【[WC/CTS2024] 水镜】
题目描述
给定一个长度为
二元组
,且 为整数;- 存在一个正实数
以及一个长度为 的序列 满足以下
所有条件: ,记 ,则 ,特别地,当 时, ; 。
, 。
solution
记
反着写一遍条件即为“区间
- 当
时你想象一下就是 是合法的。 - 当
时, 这个事实永恒不变。 - 当
时, 的减少导致 减少,所以当 时 。 - 当
时, 的减少导致 减少,所以当 时 。 - (实现时把它当做是
的限制去掉 )
这导出一个很严重的做法,即考虑固定
这里,这个区间的
抛开以上这些东西不谈我们不难发现一个区间合法那么它的子区间合法,说明它可以双指针。
【模板】不删除双指针 - caijianhong - 博客园 (cnblogs.com)
code
#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr, ##__VA_ARGS__)
#else
#define endl "\n"
#define debug(...) void(0)
#endif
typedef long long LL;
constexpr LL inf = 1e18;
struct node {
LL l, r;
bool empty() { return l > r; }
};
node cap(node a, node b) {
if (a.empty() || b.empty()) return node{inf, -inf};
if (a.l > b.l) swap(a, b);
else if (a.l == b.l && a.r > b.r) swap(a, b);
debug("cap([%lld, %lld], [%lld, %lld]) = [%lld, %lld]\n", a.l, a.r, b.l, b.r, b.l, a.r);
return node{b.l, a.r};
}
node merge(node a, node b) {
return node{min(a.l, b.l), max(a.r, b.r)};
}
node append(node a, node b) {
if (!b.empty()) {
if (b.l == -inf) a.r = max(a.r, b.r);
if (b.r == inf) a.l = min(a.l, b.l);
}
return a;
}
int n;
LL h[500010];
node I[500010], E = node{inf + 1, -inf - 1}; // E 是单位元
int main() {
#ifndef LOCAL
cin.tie(nullptr)->sync_with_stdio(false);
#endif
cin >> n;
for (int i = 1; i <= n; i++) cin >> h[i];
for (int i = 2; i < n; i++) {
node L = h[i - 1] < h[i] ? node{-inf, h[i - 1] + h[i]} : node{h[i - 1] + h[i], inf};
if (h[i - 1] == h[i]) L = node{-inf, inf};
node R = h[i] < h[i + 1] ? node{h[i] + h[i + 1], inf} : node{-inf, h[i] + h[i + 1]};
if (h[i] == h[i + 1]) R = node{-inf, inf};
I[i] = cap(L, R);
debug("I[%d] = [%lld, %lld]\n", i, I[i].l, I[i].r);
if (!I[i].empty()) assert(I[i].l == -inf || I[i].r == inf);
I[i] = append(E, I[i]);
}
LL ans = n - 1;
static node rel[500010], rer;
for (int r = 2, l, mid; r < n; ) {
for (mid = l = r, rel[l + 1] = rer = E; l > 1; --l) {
rel[l] = merge(I[l], rel[l + 1]);
if (!rel[l].empty()) break;
}
// [l, r] is invaild or l == 1
for (++l; ans += r - l + 1, ++r < n; ) {
rer = merge(rer, I[r]);
while (l <= mid && !merge(rel[l], rer).empty()) ++l;
if (l > mid) break;
}
}
cout << ans << endl;
return 0;
}
本文来自博客园,作者:caijianhong,转载请注明原文链接:https://www.cnblogs.com/caijianhong/p/18017098/solution-P10144
分类:
solution
标签:
two pointers
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】