(Optional) Longest Increasing Subsequence
Authors: Michael Cao, Benjamin Qi, Andi Qu, Andrew Wang
Prerequisites
Finding and using the LIS of an array
Resources | |||
---|---|---|---|
cp-algo | A comprehensive guide (covers almost everything here) |
Focus Problem – read through this problem before continuing!
Tutorial
In this tutorial, let be the array we want to find the LIS for.
Resources | |||
---|---|---|---|
CPH | slow solution |
Let be the length of the longest increasing subsequence that ends on . We can then naively compute (and thus the LIS) in time:
C++
1int find_lis(vector<int> a) {2 int n = a.size(), lis = 0;3 vector<int> dp(n, 1);4 for (int i = 0; i < n; i++) {5 for (int j = 0; j < i; j++)6 if (a[j] < a[i])7 dp[i] = max(dp[i], dp[j] + 1);8 lis = max(lis, dp[i]);9 }10 return lis;
Java
1public static int find_lis(int[] a) {2 int n = a.length, lis = 0;3 int[] dp = new int[n]; Arrays.fill(dp, 1);4 for (int i = 0; i < n; i++) {5 for (int j = 0; j < i; j++)6 if (a[j] < a[i])7 dp[i] = Math.max(dp[i], dp[j] + 1);8 lis = Math.max(lis, dp[i]);9 }10 return lis;
We can do much better than this though!
Let be an array where is the smallest element from the first elements of with an increasing sequence of length ending on it (or if there is no such element).
Lemma 1: forms a non-decreasing sequence.
Proof: Assume for a contradiction that for some , we have . However, this is impossible because an increasing sequence of length ending on some element implies that there is also an increasing sequence of length ending on that same sequence.
Lemma 2: The length of the LIS ending on is equal to the least index such that .
Proof: Firstly, since , there is an increasing sequence of length ending on . By Lemma 1, is non-decreasing, so for all . This means that the length of the LIS is .
Lemma 3: Exactly 1 element differs between and .
Proof: Obviously, we need to set to be since . We don't update anything else though, since for all and there are no increasing sequences ending on of length greater than .
To find and update the described in time, we can use a std::vector
and std::lower_bound
. Alternatively, we can use a std::set
(demonstrated in the solution for PCB).
C++
1int find_lis(vector<int> a) {2 vector<int> dp;3 for (int i : a) {4 int pos = lower_bound(dp.begin(), dp.end(), i) - dp.begin();5 if (pos == dp.size()) dp.push_back(i);6 else dp[pos] = i;7 }8 return dp.size();9}
Java
1public static int find_lis(int[] a) {2 ArrayList<Integer> dp = new ArrayList<Integer>();3 for (int i : a) {4 int pos = Collections.binarySearch(dp, i);5 if(pos < 0) pos = Math.abs(pos + 1);6 if (pos == dp.size()) dp.add(i);7 else dp.set(pos, i);8 }9 return dp.size();10}
Example - PCB
Focus Problem – read through this problem before continuing!
This problem asks us to find the minimum number of disjoint sets of non-intersecting segments. This seems quite intimidating, so let's break it up into two parts:
- Finding a set of non-intersecting segments
- Minimizing the number of these sets
Application 1 - Non-intersecting Segments
First, what can we say about two segments and if they intersect (assuming )?
Since these segments are straight, notice how .
This means that a set of non-intersecting segments satisfies for all pairs !
Let be an array where means that the segment with its right endpoint at position has its left endpoint at position .
If we were asked to find the maximum size of a set of non-intersecting segments, the answer would be the LIS of !
Application 2 - Minimum Number of Increasing Sequences
Continuing from application 1, we now want to find the minimum number of increasing subsequences required to cover .
Luckily for us, there's a simple (though not so obvious) solution to this.
Lemma (Easy): The minimum number of increasing subsequences required to cover is at least the size of longest non-increasing subsequence of .
Proof: No two elements of any non-increasing subsequence can be part of the same increasing subsequence.
Claim: The minimum number of increasing subsequences required to cover is equal to the size of longest non-increasing subsequence of !
Wrong Proof 1: See cp-algo (note that this link describes partitioning into non-increasing subsequences rather than increasing subsequences). However, it's not correct because the process of unhooking and reattaching might never terminate. For example, consider partitioning into the non-increasing subsequences and . Then will be moved from the front of to the front of on the first step, back to on the second step, and so on.
Wrong Proof 2: This is essentially the same as the above.
Motivation: Consider the obvious greedy strategy to construct the collection of increasing subsequences (essentially patience sorting). For each element of from left to right, add it to the increasing subsequence with last element less than such that the value of this last element is maximized. If no such increasing subsequence currently exists, then start a new increasing subsequence with .
This algorithm performs exactly the same steps as the algorithm to compute the length of the longest non-increasing subsequence, so it follows that they return the same result.
Proof: Let denote the length of longest non-increasing subsequence ending at . Then the 's satisfying for a fixed are an increasing subsequence for each . So we have covered with (size of longest non-increasing subsequence) increasing subsequences, done.
Do you see why this is equivalent to the sketch?
Alternative Proof: This is just a special case of Dilworth's Theorem. See the inductive proof.
Code
C++
1#include <bits/stdc++.h>2using namespace std;34int lis = 0;5pair<int, int> a[100000];6set<int> s;78int main() {9 iostream::sync_with_stdio(false);10 cin.tie(0);
Java
1import java.io.*;2import java.util.*;34class PCB{5 public static void main(String[] args) throws IOException6 {7 BufferedReader br = new BufferedReader(new InputStreamReader(System.in));8 int n = Integer.parseInt(br.readLine());9 TreeMap<Integer, Integer> a = new TreeMap<Integer, Integer>(Collections.reverseOrder());10 for(int i = 0; i < n; i++){
Problems
Status | Source | Problem Name | Difficulty | Tags | Solution | URL |
---|---|---|---|---|---|---|
CSES | Easy | Show TagsDP | ||||
Old Gold | Normal | Show TagsDP | External Sol | |||
LMiO | Normal | Show TagsDP | ||||
Baltic OI | Hard | Show TagsDP, Geometry | External Sol | |||
CEOI | Hard | Show TagsDP |
Module Progress:
Join the USACO Forum!
Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!