Problem:
Score : 500 points

Problem Statement

You are given a sequence with N integers: A = \{ A_1, A_2, \cdots, A_N \}.
For each of these N integers, we will choose a color and paint the integer with that color. Here the following condition must be satisfied:

If A_i and A_j (i < j) are painted with the same color, A_i < A_j.

Find the minimum number of colors required to satisfy the condition.

Constraints

1 \leq N \leq 10^5

0 \leq A_i \leq 10^9

Input

Input is given from Standard Input in the following format:

N
A_1
:
A_N

Output

Print the minimum number of colors required to satisfy the condition.

Sample Input 1

5
2
1
4
5
3

Sample Output 1

2

We can satisfy the condition with two colors by, for example, painting 2 and 3 red and painting 1, 4, and 5 blue.

Sample Input 2

4
0
0
0
0

Sample Output 2

4

We have to paint all the integers with distinct colors.

Solution in C# (Mono 4.6.2.0) (judge verdict: Wrong Answer)

using System;
using System.Numerics;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Collections;

namespace debug
{
    class main
    {
        static void Main(string[] args)
        {
            //問題クラスを展開
            ProgramE a = new ProgramE();
            a.main();//実行する

        }

    }

    class ProgramA
    {
        public void main()
        {
            //まずは数を代入する
            string input = Console.ReadLine();
            int r = int.Parse(input);

            Console.WriteLine(3 * r * r);
        }
            
    }

    class ProgramB
    {
        public void main()
        {
            string[] input = Console.ReadLine().Split(' ');
            int n = int.Parse(input[0]);
            int D = int.Parse(input[1]);

            int sum = n / (2 * D + 1);

            if (n % (2 * D + 1) == 0)
                Console.WriteLine(sum);
            else
            {
                sum++;
                Console.WriteLine(sum);
            }

        }
    }

    class ProgramC
    {
        public void main()
        {
            string input = Console.ReadLine();
            int n = int.Parse(input);

            var a_array = new List<int>();
            for (int i = 0; i < n; i++)
            {
                string input_a = Console.ReadLine();
                int a = int.Parse(input_a);
                a_array.Add(a);
            }
            int max = a_array.Max();
            int max_i = a_array.IndexOf(max);

            for (int i = 0; i < n; i++)
            {
                if (max_i != i)
                    Console.WriteLine(max);
                else
                {
                    a_array.RemoveAt(max_i + 1);
                    Console.WriteLine(a_array.Max());
                }
            }
        }
    }



    
    class ProgramD
    {
        public void main()
        {
            //
            string input = Console.ReadLine();
            int n = int.Parse(input);
            string[] inputA = Console.ReadLine().Split(' ');
            int[] A = new int[n];
            int[] ans = new int[n];
            for (int i = 0; i < n; i++)
                A[i] = int.Parse(inputA[i]);

            //まずは半分より上を考える（これらは倍数を一つしか持たない）
            for (int i = n / 2; i < n; i++)
            {
                ans[i] = A[i];
            }
            
            //減らしたとき条件が固定されていくので満たすかを確認する
            for (int i = n / 2 - 1; i >= 0; i--)
            {
                int sum = 0;
                //上の固定された条件を見る
                for (int j = i; j < n; j = j + (i + 1))
                {
                    if (j == i)
                        sum += A[j];
                    else
                        sum += ans[j];
                }
                ans[i] = sum % 2;//そこから決める
            }

            int count = 0;

            //全部数えたら確認
            for (int i = 0; i < n; i++)
            {
                if (ans[i] == 1)
                    count++;
            }

            //答え出力
            Console.WriteLine(count);

            for (int i = 0; i < n; i++)
            {
                if (ans[i] == 1)
                    Console.Write(i + 1);
                Console.Write(" ");
            }
        }
    }
    
    class ProgramE
    {
        public void main()
        {
            int n = int.Parse(Console.ReadLine());

            List<int> list = new List<int>();
            List<int> color = new List<int>();

            for (int i = 0; i < n; i++)
                list.Add(int.Parse(Console.ReadLine()));

            color.Add(list[n -1]);

            for (int i = 0; i < n - 1; i++)
            {
                int t = list[n - 2 - i];
                int min = 0;
                int max = color.Count;

                //入った数が今までより大きかったら加える
                if (color[max - 1] <= t)
                {
                    color.Add(t);
                    continue;
                }

                if(color.Count == 1)
                {
                    color[0] = t;
                    continue;
                }

                //入った数が小さいなら二分探索でt以下の最大の場所を見つけ、書き換え
                do
                {
                    int temp = (min + max) / 2;

                    if (color[temp] < t)
                        min = temp;
                    else
                        max = temp;

                }while (min + 1 != max);

                color[min] = t;
               
            }

            Console.WriteLine(color.Count);
        }
    }

    /*優先度付きキュー*/
    class PriorityQueue<T> where T : IComparable<T>
    {
        public readonly T[] Array;
        public readonly bool Greater;
        public int Count { get; private set; } = 0;


        public PriorityQueue(int capacity, bool greater = true)
        {
            this.Array = new T[capacity];
            this.Greater = greater;
        }

        //キューを追加
        public void Enqueue(T item)
        {
            this.Array[this.Count] = item;
            this.Count += 1;//数を足す
            this.UpHeap();　//最後尾に追加したところを移動させる
        }

        public T Dequeue()
        {
            // 先頭要素を末尾にして再構成
            this.Swap(0, this.Count - 1);
            this.Count -= 1;
            this.DownHeap();

            return this.Array[this.Count];
        }

        //親と比較して入れ替えていく
        private void UpHeap()
        {
            var n = this.Count - 1;
            while (n != 0)
            {
                // 親要素の座標
                var parent = (n - 1) / 2;

                //もし親の方がちいさいなら、交換する。
                if (this.Compare(this.Array[n], this.Array[parent]) > 0)
                {
                    this.Swap(n, parent);
                    n = parent;
                }
                else
                {
                    break;
                }
            }
        }

        //子と比較して入れ替えていく
        private void DownHeap()
        {
            var parent = 0;
            while (true)//無限ループ
            {
                var child = 2 * parent + 1;
                //子供がいないなら終わり
                if (child > this.Count - 1) break;

                //子供は2つあるので大きい方を対象にする
                if (child < this.Count - 1 && this.Compare(this.Array[child], this.Array[child + 1]) < 0)
                {
                    // 左より右の子のほうが大きい値の場合、右を入れ替え対象にする
                    child += 1;
                }

                //親と子を比較して子が大きいなら入れ替える。そうでないなら成立なのでおしまい。
                if (this.Compare(this.Array[parent], this.Array[child]) < 0)
                {
                    this.Swap(parent, child);
                    parent = child;
                }
                else
                {
                    break;
                }
            }
        }

        //aとbを比較する
        private int Compare(T a, T b)
        {
            var c = a.CompareTo(b);//a-b、正のときはaが大きく、負のときはbが大きい（任意もので処理できる）
            if (!this.Greater)
            {
                c = -c;
            }
            return c;
        }

        //aとbを入れ替える
        private void Swap(int a, int b)
        {
            var tmp = this.Array[a];
            this.Array[a] = this.Array[b];
            this.Array[b] = tmp;
        }
    }



}