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

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

    }

    class ProgramA
    {
        public void main()
        {
            //入力
            string s = Console.ReadLine();

            if (s == "Sunny")
                Console.WriteLine("Cloudy");
            else if (s == "Cloudy")
                Console.WriteLine("Rainy");
            else
                Console.WriteLine("Sunny");

        }


    }

    class ProgramB
    {
        public void main()
        {
            //入力
            string s = Console.ReadLine();

            for(int i = 0;i < s.Length;i++)
            {
                if( i % 2 == 0)
                {
                    if(s[i] == 'L')
                    {
                        Console.WriteLine("No");
                        return;
                    }
                    continue;
                }

                if (s[i] == 'R')
                {
                    Console.WriteLine("No");
                    return;
                }
            }

            Console.WriteLine("Yes");
        }


    }

    class ProgramC
    {
        public void main()
        {
            //入力
            string[] s = Console.ReadLine().Split(' ');
            long n = long.Parse(s[0]);
            long k = long.Parse(s[1]);
            long q = long.Parse(s[2]);

            int[] num = new int[n];

            for (int i = 0; i < q; i++)
            {
                int temp = int.Parse(Console.ReadLine());
                num[temp - 1]++;
            }

            for (int i = 0; i < n; i++)
            {
                if(k - (q - num[i]) > 0)
                    Console.WriteLine("Yes");
                else
                    Console.WriteLine("No");
            }
        }


    }

    class ProgramD
    {
        public void main()
        {
            string[] s = Console.ReadLine().Split(' ');
            int n = int.Parse(s[0]);
            int m = int.Parse(s[1]);

            string[] a = Console.ReadLine().Split(' ');

            PriorityQueue<long> p = new PriorityQueue<long>(n);


            for (int i = 0; i < n; i++)
                p.Enqueue(long.Parse(a[i]));

            for (int i = 0; i < m; i++)
            {
                long t = p.Dequeue();
                t /= 2;
                p.Enqueue(t);
            }

            long ans = 0;

            for (int i = 0; i < n; i++)
                ans += p.Dequeue();

            Console.WriteLine(ans);


        }

    }

    /*優先度付きキュー*/
    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;

                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);
            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;
        }
    }

    class ProgramE
    {
        public void main()
        {
            //入力
            int n = int.Parse(Console.ReadLine());
            string s = Console.ReadLine();

            
            
            int ans = 0;
            //開始文字位置
            for (int moji = 1; moji < n; moji++)
            {
                string s_sub = s.Substring(moji - 1);
                //初期設定
                int[] A = new int[s_sub.Length];
                A[0] = s_sub.Length;
                int i = 1;
                int j = 0;
                //zアルゴリズムを使って解く（計算量o(N))
                while (i < s_sub.Length)
                {
                    //基本は比較を行う
                    while (i + j < s_sub.Length && s_sub[j] == s_sub[i + j])
                        j++;
                    A[i] = j;

                    //一致するものがないなら次のものを考える
                    if (j == 0)
                    {
                        i++;
                        continue;
                    }

                    //一致する文字があるならそれ以降は飛ばして処理する
                    int k = 1;
                    while (k < j && A[k] + k < j)//1、２回目把握した数内で収まるならイコール処理する
                    {
                        A[i + k] = A[k];
                        k++;
                    }

                    i += k;//確定したら進める
                    j -= k;//決まっていない分は戻る

                }

                //答としてあり得ないものは除く
                for(int t = 0;t < s_sub.Length;t++)
                {
                    if (t < A[t])
                        A[t] = 0;
                }


                ans = Math.Max(ans, A.Max());//答を代入


            }


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


        }

    }

    

}


Measured memory_bytes: 37028