Codeforces Round #669 (Div. 2) D

题解

想想应该明白, (i < j < k) i -> j ->k, 必然能够直接 i -> k

那就是线性dp了, 从 1 一直到 n 点, dp就完事, 关键是如何转移,

或者说是 i 能到达哪些点?

想想应该明白, (i < j < k) i -> j ->k, 必然能够直接 i -> k

所以我们只需要求得

正解单调栈预处理, 没啥意思, 看了rk1的代码, 有点意思

很巧妙的处理方式,

和前几天写的, 拿到前缀和处理一样巧妙, 用后续节点去更新前面的节点

至于 max h[i + 1 ~ j - 1] < min(h[i], h[j]) 和 min h[i+ 1 ~ j - 1] > max(h[i], h[j]) 本质一样的

你把 h[i] = -h[i], 不就把 max 变成 min了, 说白了相同算法, h取负数算两次就行, 那我们直接考虑 max

只要按从到大小顺序取, 那么 对于 a < b 只要不存在 c(a < c < b) 比 a, b 先取出来(h[c] > min(h[a], h[b])) a -> b 就可以连接

如果存在这个c, 且不存在 d(a < d < c) 比 a, c 先取出来(h[d] > min(h[a], h[c])) a -> c就可以连接 ...(无限套娃)

按从大到小取出 b 时, 我们能直接得到 a (已经被取出, 且所有取出的数, a,b 距离最近) 就可以链接 a -> b,

用 set 维护 取出的集合就好了!

同时我们还要考虑 b(刚被取出) -> c(c已经被取出), 我们要确保没有 d(未被取出, h[d] == h[b], d < c), 就可以 b -> c

剩下的 dp就好了

#include <bits/stdc++.h>
#define all(n) (n).begin(), (n).end()
#define se second
#define fi first
#define pb push_back
#define mp make_pair
#define sqr(n) (n)*(n)
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<ll, ll> PLL;
typedef vector<int> VI;
typedef double db;

const int N = 1e4 + 5;

int n, m, _, k, x, y;

int main() {
    IOS;
    cin >> n; VI a(n), b(n);
    vector<VI> e(n);
    for (auto& i : a) cin >> i;
    rep(i, 0, n - 1) b[i] = i;
    rep(cas, 1, 2) {
        for (auto& i : a) i = -i;
        sort(all(b), [&](int& x, int& y) {
            return tie(a[x], x) < tie(a[y], y);
        });
        set<int> st;
        rep(i, 0, n - 1) {
            st.insert(b[i]);
            auto cur = st.find(b[i]), ne = next(cur);
            if (cur != st.begin()) e[*prev(cur)].pb(b[i]);
            if (ne != st.end() && (i + 1 == n ||
                a[b[i + 1]] != a[b[i]] || b[i + 1] > * ne)) e[b[i]].pb(*ne);
        }
    }
    VI f(n, 1e8); f[0] = 0;
    rep(i, 0, n - 1)
        for (auto& j : e[i]) f[j] = min(f[j], f[i] + 1);
    cout << f[n - 1] << '
';
    return 0;
}
原文地址:https://www.cnblogs.com/2aptx4869/p/13638578.html