zoukankan      html  css  js  c++  java
  • 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 ext{ : } 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 != '
    ') && (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 = '';
            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('
    ');
        }
    
        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 << "33[31m" << "[" << __LINE__ << "] : "; _dbg(#__VA_ARGS__, __VA_ARGS__); cerr << "33[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 << "33[32mTime Elasped: " << duration.count() << " ms33[0m" << endl;
    #endif
        return 0;
    }
    
  • 相关阅读:
    linux性能监控三张图
    golang 之 defer(统计函数执行时间)
    golang之匿名函数
    php opcodes运行原理
    Mysql索引的类型
    字符串反转方法收集
    curl模拟请求常用参数
    windows10 使用gitblit搭建git服务器
    PHP程序员解决问题的能力
    mysql中union 查询
  • 原文地址:https://www.cnblogs.com/zengzk/p/14192744.html
Copyright © 2011-2022 走看看