codeforces1468A LaIS (DP)

题意

给出一个数组\(a\),输出满足\(\min(b_1, b_2) \le \min(b_2, b_3) \le \min(b_3, b_4) \dots\)的子序列\(b\)的最长长度。

解法

观察

首先想到LIS,然后这题和LIS的区别就是,两个LIS的元素中间可以插入一个更大的元素

然后这个性质转化一下,就是:假设一个LaIS以\(a_i\)结尾,则如果\(a_i \le a_j\)则可以在其结尾插入\(a_j\);或者,若存在\(i < k < j\)\(a_i \le a_j,a_k \ge a_j\),则可以在其结尾插入\(a_k, a_j\)

具体做法

根据这个性质,假设\(dp_i\)为以\(a_i\)结尾的最长长度,\(f_i\)为以\(i\)结尾的最长长度。

第一种转移

第一种转移比较简单,就是

\[dp_i = \max_{0 \le v \le a_i} \{ f_v \} + 1 \]

第二种转移

第二种转移复杂一点,如果有\(j < i\)\(a_j \ge a_i\),则可以通过第二种转移更新答案,但是如果在\(i\)处更新答案,则有可能会违反子序列的顺序不变性质,这个是不正确的,所以这种转移要提前到\(j\)处做。

而且因为至多只能多插一个,所以不会有比用满足条件且离得最近的\(j\)来转移更优的方案。所以就可以用一个单调栈处理出所有\(i\)处对应的\(j\),且反过来\(j\)对应的\(i\)的集和\(nxt_j\)也可以求出来。

至此,第二种转移方式就是

\[\forall x \in nxt_j \text{ : } dp_x = \max_{0 \le v \le x} \{ f_v \} + 2 \]

最后

每次处理完\(dp_i\)之后,应该要用\(dp_i\)去更新\(f_{a_i}\)

最后的答案就是\(\max_{0 \le v \le n} \{ f_v \}\)

优化

两种转移方式都用到了一个前缀最大值查询以及单点更新最大值。这个就是线段树基本功能了。

然后因为只有前缀最大值查询,而不是区间最大值查询,不涉及区间信息可减性,所以树状数组也可以处理。

AC代码

#include <bits/stdc++.h>
using namespace std;
 
using ll = int64_t;
using ull = uint64_t;
using uint = uint32_t;
using VI = vector<int>;
using VL = vector<ll>;
using VVI = vector<vector<int>>;
using VVL = vector<vector<ll>>;
using PII = pair<int,int>;
using PLL = pair<ll, ll>;
 
#define REP(i, _, __) for (int i = (_); i < (__); ++i)
#define PER(i, _, __) for (int i = (_-1); i >= (__); --i)
#define FOR(i, _, __) for (int i = (_); i <= (__); ++i)
#define ROF(i, _, __) for (int i = (_); i >= (__); --i)
#define FC(v, V) for (const auto& v: V)
#define FE(v, V) for (auto& v: V)

#define EB emplace_back
#define PB push_back
#define MP make_pair
#define FI first
#define SE second
#define SZ(x) (int((x).size()))
#define ALL(x) (x).begin(),(x).end()
#define LLA(x) (x).rbegin(),(x).rend()

const double PI = acos(-1.0);
   
namespace Backlight {
    const int __BUFFER_SIZE__ = 1 << 20;
    bool NEOF = 1;
    int __top;
    char __buf[__BUFFER_SIZE__], *__p1 = __buf, *__p2 = __buf, __stk[996];

    template<typename T>
    T MIN(T a, T b) { return min(a, b); }

    template<typename First, typename... Rest>
    First MIN(First f, Rest... r) { return min(f, MIN(r...)); }

    template<typename T>
    T MAX(T a, T b) { return max(a, b); }

    template<typename First, typename... Rest>
    First MAX(First f, Rest... r) { return max(f, MAX(r...)); }

    template<typename T>
    void updMin(T& a, T b) { if (a > b) a = b; }

    template<typename T>
    void updMax(T& a, T b) { if (a < b) a = b; }

    inline char nc() {
        return __p1 == __p2 && NEOF && (__p2 = (__p1 = __buf) + fread(__buf, 1, __BUFFER_SIZE__, stdin), __p1 == __p2) ? (NEOF = 0, EOF) : *__p1++;
    }
   
    template<typename T>
    inline bool read(T &x) {
        char c = nc();
        bool f = 0; x = 0;
        while (!isdigit(c)) c == '-' && (f = 1), c = nc();
        while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = nc();
        if (f) x = -x;
        return NEOF;
    }

    inline bool need(char c) { return (c != '\n') && (c != ' '); }

    inline bool read(char& a) {
        while ((a = nc()) && need(a) && NEOF) ;
        return NEOF;
    }

    inline bool read(char *a) {
        while ((*a = nc()) && need(*a) && NEOF) ++a; 
        *a = '\0';
        return NEOF;
    }

    inline bool read(double &x) {
        bool f = 0; char c = nc(); x = 0;
        while (!isdigit(c))  { f |= (c == '-'); c = nc(); }
        while (isdigit(c)) { x = x * 10.0 + (c ^ 48); c = nc(); }
        if (c == '.') {
            double temp = 1; c = nc();
            while (isdigit(c)) { temp = temp / 10.0; x = x + temp * (c ^ 48); c = nc(); }
        }
        if (f) x = -x;
        return NEOF;
    }

    template<typename First, typename... Rest>
    inline bool read(First &f, Rest &... r) {
        read(f);
        return read(r...);
    }

    template<typename T>
    inline void print(T x) {
        if (x < 0) putchar('-'), x = -x;
        if (x == 0) { putchar('0'); return; }
        __top = 0;
        while(x) {
            __stk[++__top] = x % 10 + '0';
            x /= 10;
        }
        while(__top) {
            putchar(__stk[__top]);
            --__top;
        }
    }

    template<typename First, typename... Rest>
    inline void print(First f, Rest... r) {
        print(f); putchar(' ');
        print(r...);
    }

    template<typename T>
    inline void println(T x) {
        print(x); 
        putchar('\n');
    }

    template<typename First, typename... Rest>
    inline void println(First f, Rest... r) {
        print(f); putchar(' ');
        println(r...);
    }

    template<typename T>
    inline void _dbg(const char *format, T value) { cerr << format << '=' << value << endl; }
   
    template<typename First, typename... Rest>
    inline void _dbg(const char *format, First f, Rest... r) {
        while(*format != ',') cerr << *format++;
        cerr << '=' << f << ", ";
        _dbg(format + 1, r...);
    }
      
    template<typename T>
    ostream &operator<<(ostream& os, vector<T> V) {
        os << "[ "; for (auto v : V) os << v << ","; return os << " ]";
    }
   
    template<typename T>
    ostream &operator<<(ostream& os, set<T> V) {
        os << "[ "; for (auto v : V) os << v << ","; return os << " ]";
    }

    template<typename T>
    ostream &operator<<(ostream& os, multiset<T> V) {
        os << "[ "; for (auto v : V) os << v << ","; return os << " ]";
    }
 
    template<typename T1, typename T2>
    ostream &operator<<(ostream& os, map<T1, T2> V) {
        os << "[ "; for (auto v : V) os << v << ","; return os << " ]";
    }
  
    template<typename L, typename R>
    ostream &operator<<(ostream &os, pair<L, R> P) {
        return os << "(" << P.first << "," << P.second << ")";
    }

    #ifdef BACKLIGHT
    #define debug(...) cerr << "\033[31m" << "[" << __LINE__ << "] : "; _dbg(#__VA_ARGS__, __VA_ARGS__); cerr << "\033[0m";
    // #define debug(...) _dbg(#__VA_ARGS__, __VA_ARGS__); 
    #else
    #define debug(...)
    #endif
}

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
int rnd(int l, int r) { return l + rng() % (r - l + 1); }

using namespace Backlight;
const int N = 5e5 + 5;
const int M = 3e6 + 5;
const int K = 1e7 + 5;
const int MOD = 1e9 + 7;              // 998244353 1e9 + 7
const int INF = 0x3f3f3f3f;             // 1e9 + 7 0x3f3f3f3f
const ll LLINF = 0x3f3f3f3f3f3f3f3f;    // 1e18 + 9 0x3f3f3f3f3f3f3f3f
const double eps = 1e-8;

struct FenwickTree {
    int n;
    vector<int> c;

    FenwickTree(int _n) : n(_n), c(n + 1) {}

    inline int lb(int x) { return x & -x; }

    void upd(int x, int v) {
        for (; x <= n; x += lb(x))
            updMax(c[x], v);
    }

    int qry(int x) {
        int r = 0;
        for(; x; x -= lb(x))
            updMax(r, c[x]);
        return r;
    }
};

int n, a[N], dp[N];
int top, s[N], pre[N];
vector<int> nxt[N];
void solve(int Case) { // printf("Case #%d: ", Case);
    read(n);
    FOR(i, 1, n) nxt[i].clear(), dp[i] = 0;
    FOR(i, 1, n) read(a[i]);
    
    top = 0;
    FOR(i, 1, n) {
        while(top > 0 && a[i] >= a[s[top]]) --top;
        pre[i] = s[top];
        s[++top] = i;
        if (pre[i] != 0) nxt[pre[i]].PB(i);
    }

    FenwickTree t(n);
    FOR(i, 1, n) {
        updMax(dp[i], t.qry(a[i]) + 1);
        for (int x: nxt[i]) {
            updMax(dp[x], t.qry(a[x]) + 2);
        }
        t.upd(a[i], dp[i]);
    }
    println(t.qry(n));
}


int main() {
#ifdef BACKLIGHT
    freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    auto begin = std::chrono::steady_clock::now();
#endif

    // ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int T = 1;
    read(T);
    for (int _ = 1; _ <= T; _++) solve(_);

#ifdef BACKLIGHT
    auto end = std::chrono::steady_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin);
    cerr << "\033[32mTime Elasped: " << duration.count() << " ms\033[0m" << endl;
#endif
    return 0;
}
posted @ 2020-12-26 14:20  _Backl1ght  阅读(190)  评论(0编辑  收藏  举报