#include <iostream>
#include <vector>
#include <array>
#include <deque>
#include <stack>
#include <queue>
#include <list>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <algorithm>
#include <numeric>
#include <utility>
#include <cmath>
#include <iomanip>
#include <cassert>
#include <complex>
#include <bitset>
#include <functional>
#include <chrono>

using namespace std;
using ll=long long int;

template <typename T>
T powint(T a, ll n) {
    T ret = 1;
    while (n > 0) {
        if (n & 1) ret *= a; 
        a *= a;
        n >>= 1;
    }
    return ret;
}

template <ll mod>
class ModInt {
private:
    ll num;
public:
    ModInt() {};
    ModInt(ll n) { num = n % mod; }
    ModInt inv() const { return powint(*this, mod-2); }
    explicit operator ll() const { return num; }

    ModInt& operator+=(const ModInt& a) {
        num += a.num; 
        if (num >= mod) num -= mod; 
        return *this;
    }
    ModInt& operator-=(const ModInt& a) {
        if (num < a.num) num += mod;
        num -= a.num;
        return *this;
    }
    ModInt& operator*=(const ModInt& a) {
        num = num * a.num % mod;
        return *this;
    }
    ModInt& operator/=(const ModInt& a) { return *this *= a.inv(); }
    friend ModInt operator+(const ModInt& a, const ModInt& b) { return ModInt(a) += b; }
    friend ModInt operator-(const ModInt& a, const ModInt& b) { return ModInt(a) -= b; }
    friend ModInt operator*(const ModInt& a, const ModInt& b) { return ModInt(a) *= b; }
    friend ModInt operator/(const ModInt& a, const ModInt& b) { return ModInt(a) /= b; }

    friend ostream& operator<<(ostream& os, const ModInt& a) { return os << a.num; }
    friend istream& operator>>(istream& is, ModInt& a) {
        ll tmp;
        is >> tmp;
        a.num = tmp % mod;
        return is;
    }
};
// using mint = ModInt<1000000007>;
// using mint = ModInt<998244353>;

const ll mmod = (1LL << 61) - 1;
template<>
ModInt<mmod>& ModInt<mmod>::operator*=(const ModInt<mmod>& a) {
    const ll mask31 = (1LL << 31) - 1;
    const ll mask30 = (1LL << 30) - 1;
    ll ah = num >> 31, al = num & mask31;
    ll bh = a.num >> 31, bl = a.num & mask31;
    ll t = ah * bl + al * bh;
    ll th = t >> 30, tl = t & mask30;
    num = (ah * bh << 1) + th + (tl << 31) + al * bl;

    num = (num >> 61) + (num & mmod);
    if (num >= mmod) num -= mmod;
    return *this;
}

const ll rndbase = 128 + chrono::steady_clock::now().time_since_epoch().count() % 100000;
template<ll mod>
struct RollingHash {
    using mint = ModInt<mod>;
    vector<mint> hash, power;

    RollingHash(string &s, ll base = rndbase) {
        int n = s.size();
        power.resize(n+1);
        hash.resize(n+1);
        power[0] = 1; hash[0] = 0;
        for (int i = 0; i < n; i++) {
            power[i+1] = power[i] * base;
            hash[i+1] = hash[i] * base + s[i];
        }
    }

    ll get(int l, int r) {
        return (ll)(hash[r] - hash[l] * power[r - l]);
    }
};

template<ll ...mod>
struct RollingHashMultiMod {
    tuple<RollingHash<mod>...> hashlist;
    RollingHashMultiMod(string &s, ll base = rndbase)
        : hashlist(RollingHash<mod>(s, base)...) {}
    auto get(int l, int r) {
        return get(l, r, make_index_sequence<sizeof...(mod)>{});
    }
    template<size_t... I>
    auto get(int l, int r, index_sequence<I...>) {
        return array<ll, sizeof...(mod)>{std::get<I>(hashlist).get(l, r)...};
        // return make_tuple(std::get<I>(hashlist).get(l, r)...);
    }
};
using RH = RollingHashMultiMod<1000000007, 1000000009>;

int main() {
    int n;
    cin >> n;
    string s; 
    cin >> s;

    int ans = 0;
    RH rh(s);

    for (int i = 0; i < n; i++) {
        for (int j = i; j < n; j++) {
            while (ans < j-i && j+ans < n) {
                int l = ans+1;
                if (rh.get(i, i+l) != rh.get(j, j+l)) break;
                ans++;
            }
        }
    }

    cout << ans << endl;

    return 0;
}


Measured memory_bytes: 512