#include<iostream>

template<long long modulus>
class ModInt{
    long long num;

    long long mod(long long n){
        if(n < 0LL){
            n = (n % modulus) + modulus;
        }
        return n % modulus;
    }

    long long ext_gcd(long long a, long long b, long long &x, long long &y){
        if(b == 0LL){
            x = 1;
            y = 0;
            return a;
        }

        long long d = ext_gcd(b, a % b, y, x);
        y -= a / b * x;

        return d;
    }

    long long get_inv(long long n){
        long long x, y;
        ext_gcd(n, modulus, x, y);
        return mod(x);
    }

public:
    ModInt(long long n = 0LL){
        num = mod(n);
    }

    long long get(void){
        return num;
    }

    ModInt &operator+=(const ModInt &rhs){
        num += rhs.num;
        if(num >= modulus){
            num -= modulus;
        }
        return *this;
    }

    ModInt &operator-=(const ModInt &rhs){
        if(num < rhs.num){
            num += modulus;
        }
        num -= rhs.num;
        return *this;
    }

    ModInt &operator*=(const ModInt &rhs){
        num = num * rhs.num % modulus;
        return *this;
    }

    ModInt &operator/=(const ModInt &rhs){
        long long inv = get_inv(rhs.num);
        num = num * inv % modulus;
        return *this;
    }

    template<typename T>
    ModInt &operator+=(const T &rhs){
        return *this += ModInt(rhs);
    }

    template<typename T>
    ModInt &operator-=(const T &rhs){
        return *this -= ModInt(rhs);
    }

    template<typename T>
    ModInt &operator*=(const T &rhs){
        return *this *= ModInt(rhs);
    }

    template<typename T>
    ModInt &operator/=(const T &rhs){
        return *this /= ModInt(rhs);
    }

    template<typename T>
    ModInt operator+(const T &rhs) const {
        return ModInt(*this) += ModInt(rhs);
    }

    template<typename T>
    ModInt operator-(const T &rhs) const {
        return ModInt(*this) -= ModInt(rhs);
    }

    template<typename T>
    ModInt operator*(const T &rhs) const {
        return ModInt(*this) *= ModInt(rhs);
    }

    template<typename T>
    ModInt operator/(const T &rhs) const {
        return ModInt(*this) /= ModInt(rhs);
    }

    ModInt &operator=(const ModInt &rhs){
        num = rhs.num;
        return *this;
    }

    template<typename T>
    ModInt &operator=(const T &rhs){
        num = mod(rhs);
        return *this;
    }

    bool operator<(const ModInt &rhs) const {
        return num < rhs.num;
    }
};

template<long long modulus>
std::istream &operator>>(std::istream &lhs, ModInt<modulus> &rhs){
    long long val;
    lhs >> val;
    rhs = val;
    return lhs;
}

template<long long modulus>
std::ostream &operator<<(std::ostream &lhs, ModInt<modulus> rhs){
    lhs << rhs.get();
    return lhs;
}

#include<vector>
#include<cstdlib>
#include<ctime>
#include<algorithm>

constexpr long long mod1 = 2147483587LL;
constexpr long long mod2 = 3037000453LL;

class RollingHash{
    using mint1 = ModInt<mod1>;
    using mint2 = ModInt<mod2>;

    std::vector<mint1> hash1, power1;
    std::vector<mint2> hash2, power2;

    mint1 base1;
    mint2 base2;

    int n;

public:
    RollingHash(std::string s = ""){
        std::srand(time(nullptr));

        base1 = rand();
        if(base1.get() < 1024){
            base1 -= 1024;
        }
        base2 = rand();
        if(base2.get() < 1024){
            base2 -= 1024;
        }

        n = (int)s.size();

        hash1.assign(n + 1, mint1(0));
        hash2.resize(n + 1, mint2(0));
        power1.resize(n + 1, mint1(1));
        power2.resize(n + 1, mint2(1));
        for(int i = 0 ; i < n ; ++i){
            hash1[i + 1] = hash1[i] * base1 + s[i];
            hash2[i + 1] = hash2[i] * base2 + s[i];
            power1[i + 1] = power1[i] * base1;
            power2[i + 1] = power2[i] * base2;
        }
    }

    long long get(int l, int r) const {
        long long res = (hash1[r] - hash1[l] * power1[r - l]).get();
        res *= mod2;
        res += (hash2[r] - hash2[l] * power2[r - l]).get();
        return res;
    }

    int get_LCP(const RollingHash& b, int l1, int r1, int l2, int r2){
        int len = std::min(r1 - l1, r2 - l2);
        int low = -1, high = len + 1;
        while(high - low > 1){
            int mid = (low + high) >> 1;
            if(get(l1, l1 + mid) == b.get(l2, l2 + mid)){
                low = mid;
            }else{
                high = mid;
            }
        }
        return low;
    }

    int size(void){
        return n;
    }
};

using namespace std;

int main(){
    int n;
    string s;

    cin >> n >> s;

    RollingHash rh(s);

    int ans = 0;
    for(int i = 0 ; i < n ; ++i){
        for(int j = i + 1 ; j < n ; ++j){
            ans = max(ans, rh.get_LCP(rh, i, j, j, n));
        }
    }

    cout << ans << endl;

    return 0;
}

Measured memory_bytes: 764