import java.util.*;

// https://en.wikipedia.org/wiki/Longest_increasing_subsequence
public class Lis2 {

	public static int[] lis(int[] a) {
		int n = a.length;
		int[] tail = new int[n];
		int[] prev = new int[n];

		int len = 0;
		for (int i = 0; i < n; i++) {
			int pos = lower_bound(a, tail, len, a[i]);
			len = Math.max(len, pos + 1);
			prev[i] = pos > 0 ? tail[pos - 1] : -1;
			tail[pos] = i;
		}

		int[] res = new int[len];
		for (int i = tail[len - 1]; i >= 0; i = prev[i]) {
			res[--len] = a[i];
		}
		return res;
	}

	static int lower_bound(int[] a, int[] tail, int len, int key) {
		int lo = -1;
		int hi = len;
		while (hi - lo > 1) {
			int mid = (lo + hi) >>> 1;
			if (a[tail[mid]] < key) {
				lo = mid;
			} else {
				hi = mid;
			}
		}
		return hi;
	}

	public static int lisSize(int[] a) {
		NavigableSet<Integer> s = new TreeSet<>();
		for (int v : a)
			if (s.add(v)) {
				Integer higher = s.higher(v);
				if (higher != null)
					s.remove(higher);
			}
		return s.size();
	}

	// random test
	public static void main(String[] args) {
		Random rnd = new Random(1);
		for (int step = 0; step < 10_000; step++) {
			int n = rnd.nextInt(10) + 1;
			int[] a = rnd.ints(n, 0, 10).toArray();
			int[] lis = lis(a);
			checkLis(a, lis);
			if (lis.length != lisSize(a) || lis.length != lisSize2(a))
				throw new RuntimeException();
		}
	}

	static int lisSize2(int[] a) {
		int[] last = new int[a.length];
		Arrays.fill(last, Integer.MAX_VALUE);
		int len = 0;
		for (int v : a) {
			int pos = lower_bound(last, v);
			last[pos] = v;
			len = Math.max(len, pos + 1);
		}
		return len;
	}

	static int lower_bound(int[] a, int key) {
		int lo = -1;
		int hi = a.length;
		while (hi - lo > 1) {
			int mid = (lo + hi) >>> 1;
			if (a[mid] < key) {
				lo = mid;
			} else {
				hi = mid;
			}
		}
		return hi;
	}

	static void checkLis(int[] a, int[] lis) {
		int n = a.length;
		boolean found = false;
		m1:
		for (int mask = 0; mask < 1 << n; mask++) {
			int len = Integer.bitCount(mask);
			if (len < lis.length)
				continue;
			for (int i = 0, prev = Integer.MIN_VALUE; i < n; i++)
				if ((mask & (1 << i)) != 0) {
					if (prev >= a[i])
						continue m1;
					prev = a[i];
				}
			if (len > lis.length)
				throw new RuntimeException();
			boolean ok = true;
			for (int i = 0, j = 0; i < n; i++)
				if ((mask & (1 << i)) != 0)
					ok &= a[i] == lis[j++];
			found |= ok;
		}
		if (!found)
			throw new RuntimeException();
	}
}
