Loading

[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;
}
posted @ 2025-12-26 17:37  循环一号  阅读(1)  评论(0)    收藏  举报