cplib-cpp

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub hitonanode/cplib-cpp

:heavy_check_mark: Longest increasing subsequence (LIS, 最長増加部分列)
(other_algorithms/longest_increasing_subsequence.hpp)

列の最長増加部分列 (LIS)・最長非減少部分列の長さや,これらの部分列を構成する要素の添字列を得る.

使用方法

vector<long long> A(N);

// LIS の長さ O(N log len(lis))
int lis_len = lis_length(A, LisType::StrictlyIncreasing);
// 最長非減少部分列の長さ O(N log len(lis))
int lnds_len = lis_length(A, LisType::Nondecreasing);

// LIS を構成する要素の添字列を取得 O(N log len(lis))
vector<int> lis_idxs = longest_increasing_subsequence(A, LisType::StrictlyIncreasing).get_lis_indices();

問題例

Verified with

Code

#pragma once
#include <algorithm>
#include <memory>
#include <vector>

enum class LisType {
    StrictlyIncreasing,
    Nondecreasing,
};

// Calculate (only) length of longest increasing subsequence (LIS)
// Complexity: O(n log n)
template <class T>
int lis_length(const std::vector<T> &seq, LisType lis_type = LisType::StrictlyIncreasing) {
    std::vector<T> dp;
    for (const T &x : seq) {
        if (auto itr = (lis_type == LisType::StrictlyIncreasing
                            ? std::lower_bound(begin(dp), end(dp), x)
                            : std::upper_bound(begin(dp), end(dp), x));
            itr == end(dp)) {
            dp.push_back(x);
        } else {
            *itr = x;
        }
    }
    return dp.size();
}

template <class T> struct longest_increasing_subsequence {

    LisType lis_type_ = LisType::StrictlyIncreasing;
    int current_idx = 0;

    struct Node {
        std::shared_ptr<Node> par;
        int len, idx;
        T v;
    };

    std::vector<T> dp;
    std::vector<std::shared_ptr<Node>> ptrs;

    // Complexity: O(1)
    longest_increasing_subsequence(LisType lis_type) : lis_type_(lis_type) {}

    // Complexity: O(N log N)
    longest_increasing_subsequence(const std::vector<T> &seq, LisType lis_type)
        : lis_type_(lis_type) {
        for (const T &x : seq) add(x);
    }

    // Complexity: O(log N)
    std::shared_ptr<Node> add(const T &x) {
        auto itr =
            (lis_type_ == LisType::StrictlyIncreasing ? std::lower_bound(begin(dp), end(dp), x)
                                                      : std::upper_bound(begin(dp), end(dp), x));
        int cur = std::distance(begin(dp), itr);
        std::shared_ptr<Node> prv = (begin(dp) == itr ? nullptr : ptrs.at(cur - 1));

        std::shared_ptr<Node> node(
            new Node{prv, (prv == nullptr ? 0 : prv->len) + 1, current_idx++, x});

        if (itr == end(dp)) {
            dp.push_back(x), ptrs.push_back(node);
        } else {
            dp.at(cur) = x, ptrs.at(cur) = node;
        }
        return node;
    }

    std::shared_ptr<Node> head() const { return ptrs.empty() ? nullptr : ptrs.back(); }

    // LIS をなす添字列を出力
    // Complexity: O(N)
    std::vector<int> get_lis_indices() const {
        std::vector<int> ret;
        for (auto ptr = head(); ptr != nullptr; ptr = ptr->par) ret.push_back(ptr->idx);
        std::reverse(ret.begin(), ret.end());
        return ret;
    }
};
#line 2 "other_algorithms/longest_increasing_subsequence.hpp"
#include <algorithm>
#include <memory>
#include <vector>

enum class LisType {
    StrictlyIncreasing,
    Nondecreasing,
};

// Calculate (only) length of longest increasing subsequence (LIS)
// Complexity: O(n log n)
template <class T>
int lis_length(const std::vector<T> &seq, LisType lis_type = LisType::StrictlyIncreasing) {
    std::vector<T> dp;
    for (const T &x : seq) {
        if (auto itr = (lis_type == LisType::StrictlyIncreasing
                            ? std::lower_bound(begin(dp), end(dp), x)
                            : std::upper_bound(begin(dp), end(dp), x));
            itr == end(dp)) {
            dp.push_back(x);
        } else {
            *itr = x;
        }
    }
    return dp.size();
}

template <class T> struct longest_increasing_subsequence {

    LisType lis_type_ = LisType::StrictlyIncreasing;
    int current_idx = 0;

    struct Node {
        std::shared_ptr<Node> par;
        int len, idx;
        T v;
    };

    std::vector<T> dp;
    std::vector<std::shared_ptr<Node>> ptrs;

    // Complexity: O(1)
    longest_increasing_subsequence(LisType lis_type) : lis_type_(lis_type) {}

    // Complexity: O(N log N)
    longest_increasing_subsequence(const std::vector<T> &seq, LisType lis_type)
        : lis_type_(lis_type) {
        for (const T &x : seq) add(x);
    }

    // Complexity: O(log N)
    std::shared_ptr<Node> add(const T &x) {
        auto itr =
            (lis_type_ == LisType::StrictlyIncreasing ? std::lower_bound(begin(dp), end(dp), x)
                                                      : std::upper_bound(begin(dp), end(dp), x));
        int cur = std::distance(begin(dp), itr);
        std::shared_ptr<Node> prv = (begin(dp) == itr ? nullptr : ptrs.at(cur - 1));

        std::shared_ptr<Node> node(
            new Node{prv, (prv == nullptr ? 0 : prv->len) + 1, current_idx++, x});

        if (itr == end(dp)) {
            dp.push_back(x), ptrs.push_back(node);
        } else {
            dp.at(cur) = x, ptrs.at(cur) = node;
        }
        return node;
    }

    std::shared_ptr<Node> head() const { return ptrs.empty() ? nullptr : ptrs.back(); }

    // LIS をなす添字列を出力
    // Complexity: O(N)
    std::vector<int> get_lis_indices() const {
        std::vector<int> ret;
        for (auto ptr = head(); ptr != nullptr; ptr = ptr->par) ret.push_back(ptr->idx);
        std::reverse(ret.begin(), ret.end());
        return ret;
    }
};
Back to top page
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy