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

// macros
#define overload_rep(va_0, va_1, va_2, name, ...) name
#define rep_0(i, n) for(int i = 0; i < (n); ++i)
#define rep_1(i, x, y) for(int i = (x); i <= (y); ++i)
#define rep(...) overload_rep(__VA_ARGS__, rep_1, rep_0)(__VA_ARGS__)
#define all(a) a.begin(), a.end()
#ifndef STOP_DEBUG
#define debug(...)\
    do { cerr << boolalpha << "[" << #__VA_ARGS__ << "]:";\
    debug_cerr(__VA_ARGS__); cerr << noboolalpha; } while (0)
#else
#define debug(...)
#endif

// functions
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }
void debug_cerr() { cerr << '\n'; }
template<class Head, class... Tail>
void debug_cerr(Head head, Tail... tail) {
    cerr << ' ' << head;
    debug_cerr(tail...);
}

// cin/cout setup
struct IoSetup {
    IoSetup() {
        cin.tie(nullptr);
        ios::sync_with_stdio(false);
        cout << fixed << setprecision(20);
    }
} iosetup;

// libraries
using ulint = uint_fast64_t;
constexpr ulint RH_MOD = (1ull << 61) - 1;
constexpr ulint MASK30 = (1ull << 30) - 1;
constexpr ulint MASK31 = (1ull << 31) - 1;

constexpr ulint Calc_Mod(const ulint& x) noexcept {
    ulint res = (x & RH_MOD) + (x >> 61);
    if(res > RH_MOD)res -= RH_MOD;
    return res;
}

constexpr ulint Multiply(const ulint& a, const ulint& b) noexcept {
    ulint au = a >> 31, ad = a & MASK31;
    ulint bu = b >> 31, bd = b & MASK31;
    ulint mid = ad * bu + au * bd, midu = mid >> 30, midd = mid & MASK30;
    return Calc_Mod(au * bu * 2 + midu + (midd << 31) + ad * bd);
}

struct Rh_Base {
    uint_fast32_t base1, base2;
    Rh_Base() noexcept {
        srand((uint_fast32_t)clock() + (uint_fast32_t)time(nullptr));
        base1 = rand() % 1024 + 256;
        base2 = rand() % 1024 + 256;
    }
} RH_BASE;

struct RollingHash {
private:
 
    string str;
    size_t str_sz;
    vector<ulint> hash, pow;
 
public:
 
    RollingHash() noexcept {}
    RollingHash(const string& str_) noexcept { init(str_); }
    ~RollingHash() noexcept {}
 
    void init(const string& str_) noexcept {
        str_sz = str_.size();
        str = str_;
        hash.assign(str_sz + 1, 0);
        pow.assign(str_sz + 1, 1);
        for(size_t i = 0; i < str_sz; i++){
            hash[i + 1] = Calc_Mod(Multiply(hash[i], RH_BASE.base1) + str_[i]);
            pow[i + 1] = Multiply(pow[i], RH_BASE.base1);
        }
    }
 
    void add_string(const string& str_) noexcept {
        size_t tmp_sz = str_sz;
        str_sz += str_.size();
        str += str_;
        hash.resize(str_sz + 1);
        pow.resize(str_sz + 1);
        for(int i = tmp_sz; i < str_sz; i++){
            hash[i + 1] = Calc_Mod(Multiply(hash[i], RH_BASE.base1) + str_[i - tmp_sz]);
            pow[i + 1] = Multiply(pow[i], RH_BASE.base1);
        }
    }
 
    void add_char(const char& c) noexcept {
        str += c;
        str_sz++;
        hash.push_back(Calc_Mod(Multiply(hash.back(), RH_BASE.base1) + c));
        pow.push_back(Multiply(pow.back(), RH_BASE.base1));
    }
 
    void add_rh(const RollingHash& rh) noexcept {
        add_string(rh.get_string());
    }
 
    ulint get_hash(const size_t& l, const size_t& r) const noexcept {
        return Calc_Mod(hash[r] + RH_MOD - Multiply(hash[l], pow[r - l]));
    }
 
    ulint operator () (const size_t& l, const size_t& r) const noexcept {
        return get_hash(l, r);
    }
 
    size_t size() const noexcept {
        return str_sz;
    }
 
    size_t get_lcp(const size_t& l, const size_t& r) const noexcept {
        size_t ok = 0, ng = min(str_sz - l, str_sz - r) + 1;
        while(ng - ok > 1){
            size_t md = (ok + ng) >> 1;
            (get_hash(l, l + md) == get_hash(r, r + md) ? ok : ng) = md;
        }
        return ok;
    }
 
    string get_string() const noexcept {
        return str;
    }
 
    char operator [] (const size_t& idx) const noexcept {
        return str[idx];
    }
 
};

// declarations

// solve
int main() {

    int N;
    cin >> N;
    string S;
    cin >> S;
    RollingHash rh(S);
    size_t ans = 0;
    for(size_t i = 0; i < N - ans; ++i)for(size_t j = 0; j < i - ans; ++j){
        if(S[i] != S[j])continue;
        chmax(ans, min(rh.get_lcp(i, j), i - j));
    }
    cout << ans << '\n';

}


Measured memory_bytes: 512