#include <bits/stdc++.h>
#include <utility>
#include <iomanip>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <string>
// #include <deque>
// #include <queue>
// #include <array>
// #include <ctime>
// #include <list>
#include <map>
#include <set>
// #include <cassert>
// #include <complex>
// #include <sstream>
// #include <forward_list>
// #include <unordered_set>
// #include <unordered_map> 
// #include <ctime>
 
using namespace std;
// #include <ext/pb_ds/assoc_container.hpp> // Common file  
// #include <ext/pb_ds/tree_policy.hpp>  
// #include <functional> // for less  
// using namespace __gnu_pbds;  
 
// // Declaring ordered_set 
// typedef tree<int, 
//     null_type, 
//     less<int>, 
//     rb_tree_tag, 
//     tree_order_statistics_node_update>  
//     ordered_set;  
 
#define int long long
#define pb push_back
#define mp make_pair
#define X first
#define Y second
#define scani(n) scanf("%d",&n);
#define EPS 1e-9
#define arrinput for(int i=0; i<n; i++) cin>>arr[i];
#define sumarr for(int i=0; i<n; i++) sum+=arr[i];
#define for0(i,n) for(int i=0; i<n; i++)
#define for1(i,n) for(int i=1; i<=n; i++)
#define forr(i,n) for(int i=n-1; i>=0; i--)
#define all(v) v.begin(), v.end()
#define rall(v) v.rbegin(), v.rend()
 
typedef long long ll;  
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<pii> vii;
 
const int MOD = 1e9+7;
const int n_ = 1e5+1000;
const long double PI = acos(-1.0);
 
ll gcd (ll a, ll b) {return ( a ? gcd(b%a, a) : b );}
ll power(ll a, ll n) {ll p = 1;while (n > 0) {if(n%2) {p = p * a;} n >>= 1; a *= a;} return p;}
ll power(ll a, ll n, ll mod) {ll p = 1;while (n > 0) {if(n%2) {p = p * a; p %= mod;} n >>= 1; a *= a; a %= mod;} return p % mod;}
 
bool vowel(char ch) {
    if(ch=='a' || ch=='e' || ch=='i' || ch=='o' || ch=='u') return true;
    else return false;
}
 
int prefix_function(string s) {
    int n = (int)s.length();
    vector<int> pi(n);
    for (int i = 1; i < n; i++) {
        int j = pi[i-1];
        while (j > 0 && s[i] != s[j])
            j = pi[j-1];
        if (s[i] == s[j])
            j++;
        pi[i] = j;
    }
    return pi[n-1];
}
 
// Union-Find Disjoint Sets Library written in OOP manner, using both path compression and union by rank heuristics
class UnionFind {                                              // OOP style
private:
    vi p, rank, setSize;                       // remember: vi is vector<int>
    int numSets;
public:
    UnionFind(int N) {
        setSize.assign(N, 1); numSets = N; rank.assign(N, 0);
        p.assign(N, 0); for (int i = 0; i < N; i++) p[i] = i; }
    int findSet(int i) { return (p[i] == i) ? i : (p[i] = findSet(p[i])); }
    bool isSameSet(int i, int j) { return findSet(i) == findSet(j); }
    void unionSet(int i, int j) { 
        if (!isSameSet(i, j)) { numSets--; 
        int x = findSet(i), y = findSet(j);
        // rank is used to keep the tree short 
        if (rank[x] > rank[y]) { p[y] = x; setSize[x] += setSize[y]; }
        else                   { p[x] = y; setSize[y] += setSize[x];
                                 if (rank[x] == rank[y]) rank[y]++; } } }
    int numDisjointSets() { return numSets; }
    int sizeOfSet(int i) { return setSize[findSet(i)]; }
};

int LCSRe[5005][5005];
 
int longestRepeatedSubstring(string str) 
{ 
    int n = str.length(); 
  
    // Setting all to 0 
    memset(LCSRe, 0, sizeof(LCSRe)); 
  
    string res; // To store result 
    int res_length  = 0; // To store length of result 
  
    // building table in bottom-up manner 
    int i, index = 0; 
    for (i=1; i<=n; i++) 
    { 
        for (int j=i+1; j<=n; j++) 
        { 
            // (j-i) > LCSRe[i-1][j-1] to remove 
            // overlapping 
            if (str[i-1] == str[j-1] && 
                LCSRe[i-1][j-1] < (j - i)) 
            { 
                LCSRe[i][j] = LCSRe[i-1][j-1] + 1; 
  
                // updating maximum length of the 
                // substring and updating the finishing 
                // index of the suffix 
                if (LCSRe[i][j] > res_length) 
                { 
                    res_length = LCSRe[i][j]; 
                    index = max(i, index); 
                } 
            } 
            else
                LCSRe[i][j] = 0; 
        } 
    } 
  
    // If we have non-empty result, then insert all 
    // characters from first character to last 
    // character of string 
    if (res_length > 0) 
        for (i = index - res_length + 1; i <= index; i++) 
            res.push_back(str[i-1]); 
  
    return res.size(); 
} 

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    // int n, m;
    // cin>>n>>m;
    // int a[n];
    // for0(i,n) cin>>a[i];
    // int s = 0;
    // for0(i,n) s += a[i];
    // int x = 0;
    // for0(i,n) {
    //     int y = a[i];
    //     while(y) {
    //         x++; y/=2;
    //     }
    // }
    // if(m > x) { cout<<0; return 0; }
    // priority_queue<int> pq;
    // for0(i,n) {
    //     pq.push(a[i]);
    // }
    // for0(qwe, m) {
    //     int x = pq.top(); pq.pop();
    //     pq.push(x/2);
    // }
    // s = 0;
    // while(pq.size()) {
    //     s += pq.top(); pq.pop();
    // }
    // cout<<s;
    int n;
    cin>>n;
    string str;
    cin>>str;
    cout<<longestRepeatedSubstring(str);
    
    return 0;
}

Measured memory_bytes: 195968