#pragma GCC optimize ("O3")
#include <bits/stdc++.h>
#define ll long long
#define ld long double
using namespace std;
const int N = 5e3 + 5, p1 = 31, p2 = 51, mod1 = 1e9 + 7, mod2 = 1e9 + 9;
int n, ans, p[N], q[N], invp[N], invq[N];
string s;
vector<pair<pair<int, int>, int> >len[N];
struct Rubin_karp{
    pair<int, int> h[N];
    int add(int a, int b, int mod){
        return (a + b) % mod;
    }
    int sub(int a, int b, int mod){
        return (((a - b) % mod) + mod) % mod;
    }
    int mul(int a, int b, int mod){
        return (1ll * a * b) % mod;
    }
    pair<int, int> add(pair<int, int> a, pair<int, int> b){
        return {add(a.first, b.first, mod1), add(a.second, b.second, mod2)};
    }
    pair<int, int> sub(pair<int, int> a, pair<int, int> b){
        return {sub(a.first, b.first, mod1), sub(a.second, b.second, mod2)};
    }
    pair<int ,int> mul(pair<int, int> a, pair<int, int> b){
        return {mul(a.first, b.first, mod1), mul(a.second, b.second, mod2)};
    }
    ll fp(ll b, ll p, ll mod)
    {
        if(!p)
            return 1;
        ll res = fp(b, p / 2, mod);
        res = (res % mod * res % mod) % mod;
        if(p & 1)
            res = (res % mod * b % mod) % mod;
        return res % mod;
    }
    void pre() {
        p[0] = q[0] = invp[0] = invq[0] = 1;
        for(int i = 1; i < N; i++){
            p[i] = mul(p[i - 1],  p1, mod1);
            q[i] = mul(q[i - 1], p2, mod2);
            invp[i] = fp(p[i], mod1 - 2, mod1);
            invq[i] = fp(q[i], mod2 - 2, mod2);
        }
    }
    pair<int, int> Hash(int idx, int pos, char let, pair<int, int> cur_hash) {
        cur_hash.first = add(cur_hash.first, mul(let, p[pos], mod1), mod1);
        cur_hash.second = add(cur_hash.second, mul(let, q[pos], mod2), mod2);
        return cur_hash;
    }
    pair<int, int> Hash_all(string &s){
        pair<int, int> hv = {0, 0};
        for(int i = 0; i < s.size(); i++)
            hv = this-> Hash(i, i, s[i], hv), this->h[i] = hv;
        return hv;
    }
    pair<int, int> get_hash(int l, int r, bool zbased){
        if(l > r) swap(l, r);
        if(!l) return this-> h[r];
        pair<int, int> lh = this-> h[l - 1], rh = this-> h[r];
        rh = sub(rh, lh);
        if(zbased) rh = mul(rh, {invp[l], invq[l]});
        return rh;
    }
}rks;
bool ok(int idx){
    if(len[idx].empty()) return 0;
    sort(len[idx].begin(), len[idx].end());
    pair<int, int> last_hash;
    int last_idx;
    last_hash = len[idx][0].first;
    last_idx = len[idx][0].second;
    for(int i = 1; i < len[idx].size(); i++){
        if(len[idx][i].first != last_hash)
            last_hash = len[idx][i].first, last_idx = len[idx][i].second;
        else{
            if(abs(len[idx][i].second - last_idx) >= idx)
                return 1;
        }
    }
    return 0;
}
int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> n >> s;
    rks.pre();
    rks.Hash_all(s);
    for(int i = 0; i < n; i++){
        for(int j = i; j < n; j++){
            if(j - i + 1 > n / 2) continue;
            pair<int, int>hv = rks.get_hash(i, j, 1);
            len[j - i + 1].push_back({hv, i});
        }
    }
    int s = 1, e = n, mid;
    while(s <= e){
        mid = s + e >> 1;
        if(ok(mid))
            ans = mid, s = mid + 1;
        else
            e = mid - 1;
    }
    cout << ans << '\n';
    return 0;
}


Measured memory_bytes: 142336