using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
class Problem
{
	private int N;
	private int[] items;
	public Problem()
	{
		using (var sc = new Scan(true))
		{
			sc.Read(out N);
			items = Func.Range(0, N).Select(x => sc.ReadInt()).ToArray();
		}
	}
	private int[] memo;
	public void Solve()
	{
		memo = new int[N];
		memo[0] = 1;
		for (var n = 1; n < N; n++)
		{
			memo[n] = 1;
			for (var m = 0; m < n; m++)
				if (items[m] < items[n])
					memo[n] = Math.Max(memo[n], memo[m] + 1);
		}
		Console.WriteLine(memo.Max());
	}
}
class Program
{
	static void Main()
	{
		new Problem().Solve();
	}
}
class Scan : IDisposable
{
	private TextReader file;
	public Scan(bool useConsole) { file = useConsole ? Console.In : new StreamReader("input.txt"); }
	public void Dispose() { file.Dispose(); }
	public int ReadInt() { return int.Parse(file.ReadLine()); }
	public uint ReadUInt() { return uint.Parse(file.ReadLine()); }
	public long ReadLong() { return long.Parse(file.ReadLine()); }
	public double ReadDouble() { return double.Parse(file.ReadLine()); }
	public decimal ReadDecimal() { return decimal.Parse(file.ReadLine()); }
	public string ReadString() { return file.ReadLine(); }
	public void Read<S>(out S s)
	{
		var read = ReadMulti(Type.GetTypeCode(typeof(S))).ToArray();
		s = (S)read[0];
	}
	public void Read<S, T>(out S s, out T t)
	{
		var read = ReadMulti(Type.GetTypeCode(typeof(S)), Type.GetTypeCode(typeof(T))).ToArray();
		s = (S)read[0];
		t = (T)read[1];
	}
	public void Read<S, T, U>(out S s, out T t, out U u)
	{
		var read = ReadMulti(Type.GetTypeCode(typeof(S)), Type.GetTypeCode(typeof(T)), Type.GetTypeCode(typeof(U))).ToArray();
		s = (S)read[0];
		t = (T)read[1];
		u = (U)read[2];
	}
	public void Read<S, T, U, V>(out S s, out T t, out U u, out V v)
	{
		var read = ReadMulti(Type.GetTypeCode(typeof(S)), Type.GetTypeCode(typeof(T)), Type.GetTypeCode(typeof(U)), Type.GetTypeCode(typeof(V))).ToArray();
		s = (S)read[0];
		t = (T)read[1];
		u = (U)read[2];
		v = (V)read[3];
	}
	private IEnumerable<object> ReadMulti(params TypeCode[] types)
	{
		var inp = file.ReadLine().Split(' ');
		for (var i = 0; i < types.Length; i++)
		{
			if (types[i] == TypeCode.Int32) yield return int.Parse(inp[i]);
			else if (types[i] == TypeCode.UInt32) yield return uint.Parse(inp[i]);
			else if (types[i] == TypeCode.Int64) yield return long.Parse(inp[i]);
			else if (types[i] == TypeCode.Double) yield return double.Parse(inp[i]);
			else if (types[i] == TypeCode.Decimal) yield return decimal.Parse(inp[i]);
			else if (types[i] == TypeCode.String) yield return inp[i];
			else throw new Exception();
		}
	}
	public T[,] ReadBoard<T>(int X, int Y, Func<char, int, int, T> selector)
	{
		var array = new T[X, Y];
		for (var y = 0; y < Y; y++)
		{
			var str = ReadString();
			for (var x = 0; x < X; x++) array[x, y] = selector(str[x], x, y);
		}
		return array;
	}
}
static class Func
{
	/// <summary>
	/// Find the first number x such that pred(x) is true
	/// if pred(x) is false for all min&lt;=x&lt;max, then return max
	/// in other words, pred(max) is assumed to be true
	/// </summary>
	/// <param name="min">inclusive lower limit</param>
	/// <param name="max">exclusive upper limit</param>
	/// <param name="pred">monotonous predicate, i.e. if pred(a) and a&lt;b, then pred(b)</param>
	/// <returns>first number such that satisfy pred</returns>
	public static long FirstBinary(long min, long max, Predicate<long> pred)
	{
		var left = min;
		var right = max;
		while (left < right)
		{
			var mid = (left + right) >> 1;
			if (pred(mid)) right = mid;
			else left = mid + 1;
		}
		return left;
	}
	public static IEnumerable<int> Range(int min, int max) { for (var i = min; i < max; i++) yield return i; }
	public static decimal MeasureTime(Action action)
	{
		action();return 0;
	}
}