[CTS2024] 水镜
大力分讨得到若干限制,枚举左端点,可行的右端点是一段区间,RMQ 即可,可删双指针可以做到线性。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
// typedef __int128 i128;
typedef pair<int, int> pii;
const int N = 5e5 + 10, mod = 998244353;
template<typename T>
void dbg(const T &t) { cout << t << endl; }
template<typename Type, typename... Types>
void dbg(const Type& arg, const Types&... args) {
cout << arg << ' ';
dbg(args...);
}
namespace Loop1st {
int n, mid = 0;
ll a[N], u[N], d[N], s1[N], s2[N], t1[N], t2[N];
ll ask(int l, int r, int ex) {
if (l > ex) return 1;
if (l > mid) {
mid = r;
s1[mid + 1] = -(1ll << 60); s2[mid + 1] = 1ll << 60;
for (int i = mid; i >= l; i--) s1[i] = max(s1[i + 1], d[i]), s2[i] = min(s2[i + 1], u[i]);
t1[mid] = -(1ll << 60); t2[mid] = 1ll << 60;
}
if (r > mid) t1[r] = max(t1[r - 1], d[r]), t2[r] = min(t2[r - 1], u[r]);
if (!ex) return max(s1[l], t1[r]) < min(s2[l], t2[r]);
else return max(max(s1[l], t1[r]), d[ex]) < min(min(s2[l], t2[r]), u[ex]);
}
void main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
u[i] = 1ll << 60;
d[i] = -(1ll << 60);
}
for (int i = 2; i < n; i++) {
if (a[i] >= max(a[i - 1], a[i + 1])) d[i] = a[i] + min(a[i - 1], a[i + 1]);
if (a[i] <= min(a[i - 1], a[i + 1])) u[i] = a[i] + max(a[i - 1], a[i + 1]);
}
ll ans = 0;
for (int l = 1, r = 1; l < n; l++) {
if (r < l) r = l - 1;
while (r < n && ask(l + 1, r - 1, r)) r++;
if (ask(l + 1, r - 1, 0)) ans += r - l;
}
cout << ans << '\n';
}
}
int main() {
// freopen("data.in", "r", stdin);
// freopen("data.out", "w", stdout);
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int T = 1;
// cin >> T;
while (T--) Loop1st::main();
return 0;
}

浙公网安备 33010602011771号