using System;
using System.Linq;
using System.Collections.Generic;
using static System.Console;
using System.Text;
using System.IO;
using static System.Math;
namespace AtCoder
{
    class Program
    {
        static public long[] Sarray() { return ReadLine().Split().Select(long.Parse).ToArray(); }
        static public List<long> Slist() { return ReadLine().Split().Select(long.Parse).ToList(); }
        static long Mod = (long)998244353;
        static void Main(string[] args)
        {
            //SetOut(new StreamWriter(OpenStandardOutput()) { AutoFlush = false });
            Solve();
            //Out.Flush();
        }
        static void Solve()
        {
            var N = Sarray()[0];
            var S = ReadLine();
            var sa = new SuffixArray(S);
            var res = 0L;
            for (var i = 0; i < N; ++i)
            {
                for (var j = i + 1; j < N; ++j)
                {
                    var lcp = sa.getLCP(i, j);
                    lcp = Min(lcp, j - i);
                    res = Max(res, lcp);

                }
            }
            WriteLine(res);
        }
        class SuffixArray
        {
            int _n, _k;
            int[] _rank;
            int[] _sa;
            int[] _lcp;
            string _S;
            public SuffixArray(string s)
            {
                _n = s.Length;
                _sa = new int[_n + 1];
                _rank = new int[_n + 1];
                _lcp = new int[_n + 1];
                _S = s;
                construct_sa();
                construct_lcp();
            }
            int Compare(int i, int j)
            {
                if (_rank[i] != _rank[j]) return _rank[i] - _rank[j];
                var ri = (i + _k <= _n) ? _rank[i + _k] : -1;
                var rj = (j + _k <= _n) ? _rank[j + _k] : -1;
                return ri - rj;
            }

            void construct_sa()
            {
                for (var i = 0; i <= _n; ++i)
                {
                    _sa[i] = i;
                    _rank[i] = (i < _n) ? _S[i] : -1;
                }
                var tmp = new int[_n + 1];
                for (_k = 1; _k <= _n; _k *= 2)
                {
                    Array.Sort(_sa, Compare);
                    tmp[_sa[0]] = 0;
                    for (var i = 1; i <= _n; ++i)
                        tmp[_sa[i]] = tmp[_sa[i - 1]] + ((Compare(_sa[i - 1], _sa[i]) < 0) ? 1 : 0);
                    for (var i = 0; i <= _n; ++i)
                        _rank[i] = tmp[i];
                }
            }
            int[][] _sparse;
            int[] _height;
            void construct_lcp()
            {
                for (var i = 0; i <= _n; ++i) _rank[_sa[i]] = i;
                var cur = 0;
                _lcp[0] = 0;
                for (var i = 0; i < _n; ++i)
                {
                    var j = _sa[_rank[i] - 1];
                    if (0 < cur) --cur;
                    for (; j + cur < _n && i + cur < _n; ++cur)
                        if (_S[j + cur] != _S[i + cur]) break;
                    _lcp[_rank[i] - 1] = cur;
                }
                var n = _lcp.Length;
                var h = 0;
                while ((1 << h) < n) ++h;
                _sparse = Enumerable.Range(0, h).Select(_ => Enumerable.Range(0, 1 << h).ToArray()).ToArray();
                _height = new int[n + 1];
                for (var i = 2; i <= n; ++i) _height[i] = _height[i >> 1] + 1;
                for (var i = 0; i < n; ++i) _sparse[0][i] = _lcp[i];
                for (var i = 1; i < h; ++i)
                    for (var j = 0; j < n; ++j)
                        _sparse[i][j] = Min(_sparse[i - 1][j], _sparse[i - 1][Min(j + (1 << (i - 1)), n - 1)]);
            }
            public bool contain(string T)
            {
                var a = 0;
                var b = _n;
                while (b - a > 1)
                {
                    var c = (a + b) / 2;
                    if (_S.Substring(_sa[c]).CompareTo(T) < 0) a = c;
                    else b = c;
                }
                return _S.Substring(_sa[b]).CompareTo(T) == 0;
            }
            public int getLCP(int a, int b) => get(Min(_rank[a], _rank[b]), Max(_rank[a], _rank[b]));
            int get(int a, int b) => Min(_sparse[_height[b - a]][a], _sparse[_height[b - a]][b - (1 << _height[b - a])]);
        }
    }
}

Measured memory_bytes: 14304