#include <bits/stdc++.h>
using namespace std;

template <typename T> struct RMQ {
    // the number of elements is n.
    // the ranges of tree number is n*2-1
    // parent is (i-1)/2
    // child is 2*i+1 or 2*i+2
    const T INF = numeric_limits<T>::max();
    int n;
    vector<T> dat;
    RMQ() {}
    RMQ(int n_) : n(), dat(n_ * 4, INF) {
        int x = 1;
        while (n_ > x) {
            x *= 2;
        }
        n = x;
    }

    void init(int n_) {
        dat.resize(n_ * 4);
        fill(dat.begin(), dat.end(), INF);
        int x = 1;
        while (n_ > x) {
            x *= 2;
        }
        n = x;
    }

    void update(int i, T x) {
        i += n - 1;
        dat[i] = x;
        while (i > 0) {
            i = (i - 1) / 2; // parent
            dat[i] = min(dat[i * 2 + 1], dat[i * 2 + 2]);
        }
    }

    // the minimum element of [a,b)
    T query(int a, int b) { return query_sub(a, b, 0, 0, n); }
    T query_sub(int a, int b, int k, int l, int r) {
        if (r <= a || b <= l) {
            return INF;
        } else if (a <= l && r <= b) {
            return dat[k];
        } else {
            T vl = query_sub(a, b, k * 2 + 1, l, (l + r) / 2);
            T vr = query_sub(a, b, k * 2 + 2, (l + r) / 2, r);
            return min(vl, vr);
        }
    }
};

struct SuffixArray { // Manber & Myers O(n(logn)^2)
    string str;
    vector<int> sa;  // sa[i]: the i-th smallest suffix's index
    vector<int> lcp; //
    inline int &operator[](int i) { return sa[i]; }

    SuffixArray(const string &str_) : str(str_) {
        construct_sa();
        calc_lcp();
    }

    void init(const string &str_) {
        str = str_;
        construct_sa();
        calc_lcp();
    }

    struct CompareSA {
        int n, k;
        const vector<int> &rank;
        CompareSA(int n, int k, const vector<int> &rank_sa) : n(n), k(k), rank(rank_sa) {}
        bool operator()(int i, int j) {
            if (rank[i] != rank[j])
                return (rank[i] < rank[j]);
            else {
                int rank_ik = (i + k <= n ? rank[i + k] : -1);
                int rank_jk = (j + k <= n ? rank[j + k] : -1);
                return (rank_ik < rank_jk);
            }
        }
    };

    vector<int> rank_sa; //  str[i:i+k] is the rank_sa[i]-th smallest number
    vector<int> tmp_rank_sa;
    void construct_sa() {
        int n = (int)str.size();
        sa.resize(n + 1), lcp.resize(n + 1), rank_sa.resize(n + 1), tmp_rank_sa.resize(n + 1);
        for (int i = 0; i <= n; ++i) { // one char
            sa[i] = i;
            rank_sa[i] = i < n ? (int)str[i] : -1;
        }

        for (int k = 1; k <= n; k *= 2) {
            CompareSA csa(n, k, rank_sa);
            sort(sa.begin(), sa.end(), csa);
            tmp_rank_sa[sa[0]] = 0;
            for (int i = 1; i <= n; i++) {
                tmp_rank_sa[sa[i]] = tmp_rank_sa[sa[i - 1]] + (csa(sa[i - 1], sa[i]) ? 1 : 0);
            }
            rank_sa = tmp_rank_sa;
        }
    }

    vector<int> sa_rank;
    RMQ<int> rmq;
    void calc_lcp() {
        int n = (int)str.size();
        lcp.resize(n);
        sa_rank.resize(n + 1);
        for (int i = 0; i <= n; ++i) {
            sa_rank[sa[i]] = i;
        }
        int k = 0;
        for (int i = 0; i < n; i++) {
            if (sa_rank[i] == n) {
                k = 0;
                continue;
            }
            int j = sa[sa_rank[i] + 1];
            while (i + k < n && j + k < n && str[i + k] == str[j + k]) {
                k++;
            }
            lcp[sa_rank[i]] = k;
            if (k > 0) {
                k--;
            }
        }
        rmq.init(n + 1);
        for (int i = 0; i <= n; i++) {
            rmq.update(i, lcp[i]);
        }
    }

    // the minimum element of lcp[min(sa_rank[i],sa_rank[j]), max(...))
    // s.t. the longest commont prefix between S[i:] and S[j:]
    int get_lcp(int i, int j) { return rmq.query(min(sa_rank[i], sa_rank[j]), max(sa_rank[i], sa_rank[j])); }

    void print_sa() {
        int n = (int)sa.size();
        string tmp_str = str;
        cout << std::setw(10) << "i(rank)" << std::setw(10) << "sa[i]" << std::setw(15) << "S[sa[i]:]" << std::setw(10)
             << "lcp" << endl;
        for (int i = 0; i < n; i++) {
            cout << std::setw(10) << i << std::setw(10) << sa[i] << std::setw(15) << str.substr(sa[i], n - sa[i])
                 << std::setw(10) << lcp[i] << endl;
        }
    }
};

int main() {
    // abrakadabra
    int N;
    string str;
    cin >> N >> str;
    SuffixArray SA(str);
    // SA.print_sa();

    int res = 0;
    for (int i = 0; i < N; i++) {
        for (int j = i + 1; j < N; j++) {
            int lcp = SA.get_lcp(i, j); // the longest commont prefix between S[i:] and S[j:]
            // cout << i << "\t" << j << "\t" << lcp << endl;
            lcp = min(lcp, j - i);
            res = max(res, lcp);
        }
    }
    cout << res << endl;

    return 0;
}


Measured memory_bytes: 512