//#define _GLIBCXX_DEBUG
#include "bits/stdc++.h"

using namespace std;

//------------------------------- Type Names -------------------------------//

using i64 = int_fast64_t;

using seika = string;
//{akari : 1D, yukari : 2D, maki : 3D} vector
template <class kizuna>
using akari = vector<kizuna>;
template <class yuzuki>
using yukari = akari<akari<yuzuki>>;
template <class tsurumaki>
using maki = akari<yukari<tsurumaki>>;
//{akane : ascending order, aoi : decending order} priority queue
template <class kotonoha>
using akane = priority_queue<kotonoha, akari<kotonoha>, greater<kotonoha>>;
template <class kotonoha>
using aoi = priority_queue<kotonoha>;

//------------------------------- Libraries ---------------------------------//

class RollingHash
{
    const unsigned base1 = 10009, base2 = 10007;
    //const unsigned base1 = 1007, base2 = 2009;
    const unsigned mod1 = 1000000007, mod2 = 1000000009;
    vector<unsigned> hash1, hash2, power1, power2;

    inline unsigned mul(unsigned a, unsigned b, unsigned mod) const
    {
        unsigned long long x = (unsigned long long)a * b;
        unsigned xh = (unsigned)(x >> 32), xl = (unsigned)x, d, m;
        asm("divl %4; \n\t"
            : "=a"(d), "=d"(m)
            : "d"(xh), "a"(xl), "r"(mod));
        return m;
    }

public:
    RollingHash(const string &s)
    {
        int n = (int)s.size();
        hash1.assign(n + 1, 0);
        hash2.assign(n + 1, 0);
        power1.assign(n + 1, 1);
        power2.assign(n + 1, 1);
        for (int i = 0; i < n; ++i)
        {
            hash1[i + 1] = mul(hash1[i], base1, mod1) + s[i];
            hash2[i + 1] = mul(hash2[i], base2, mod2) + s[i];
            power1[i + 1] = mul(power1[i], base1, mod1);
            power2[i + 1] = mul(power2[i], base2, mod2);
            if (hash1[i + 1] >= mod1)
            {
                hash1[i + 1] -= mod1;
            }
            if (hash2[i + 1] >= mod2)
            {
                hash2[i + 1] -= mod2;
            }
        }
    }

    //[l, r)
    inline pair<unsigned, unsigned> get(int l, int r) const
    {
        unsigned res1, res2;
        res1 = hash1[r] + mod1 - mul(hash1[l], power1[r - l], mod1);
        if (res1 >= mod1)
        {
            res1 -= mod1;
        }
        res2 = hash2[r] + mod2 - mul(hash2[l], power2[r - l], mod2);
        if (res2 >= mod2)
        {
            res2 -= mod2;
        }
        return {res1, res2};
    }

    //[l, r)
    inline unsigned getF(int l, int r) const
    {
        unsigned res;
        res = hash1[r] + mod1 - mul(hash1[l], power1[r - l], mod1);
        if (res >= mod1)
        {
            res -= mod1;
        }
        return res;
    }

    inline pair<unsigned, unsigned> connect(const pair<unsigned, unsigned> &h1, const pair<unsigned, unsigned> &h2, int h2len) const
    {
        unsigned res1, res2;
        res1 = mul(h1.first, power1[h2len], mod1) + h2.first;
        if (res1 >= mod1)
        {
            res1 -= mod1;
        }
        res2 = mul(h1.second, power2[h2len], mod2) + h2.second;
        if (res2 >= mod2)
        {
            res2 -= mod2;
        }
        return {res1, res2};
    }

    inline int LCP(const RollingHash &b, int l1, int r1, int l2, int r2)
    {
        int len = min(r1 - l1, r2 - l2);
        int ok = 0, ng = len + 1;
        while (ok + 1 < ng)
        {
            int mid = (ok + ng) / 2;
            (get(l1, l1 + mid) == b.get(l2, l2 + mid) ? ok : ng) = mid;
        }
        return ok;
    }

    inline int LCP(int l1, int r1, int l2, int r2)
    {
        int len = min(r1 - l1, r2 - l2);
        int ok = 0, ng = len + 1;
        while (ok + 1 < ng)
        {
            int mid = (ok + ng) / 2;
            (getF(l1, l1 + mid) == getF(l2, l2 + mid) ? ok : ng) = mid;
        }
        return ok;
    }
};

// verified @ https://onlinejudge.u-aizu.ac.jp/status/users/sifi_border/submissions/1/ALDS1_14_B/judge/4050289/C++14

//------------------------------- Dubug Functions ---------------------------//
inline void print()
{
    cout << endl;
}
template <typename First, typename... Rest>
void print(const First &first, const Rest &... rest)
{
    cout << first << ' ';
    print(rest...);
}
//------------------------------- Solver ------------------------------------//

void solve()
{
    int n;
    seika s;
    cin >> n >> s;
    RollingHash rh(s);
    int ans = 0;
    for (int l1 = 0; l1 < n; l1++)
        for (int l2 = l1 + 1; l2 < n; l2++)
        {
            ans = max(ans, rh.LCP(l1, l2, l2, n));
        }
    cout << ans << endl;
}

int main()
{
    solve();
    return 0;
}


Measured memory_bytes: 512