#include<bits/stdc++.h>

#define int long long
using namespace std;
#define rep(i, n) for(int i=0;i<(n);++i)
typedef pair<int, int> pii;
const int INF = 1l << 60;
#define u_b upper_bound
#define l_b lower_bound

template<int M = 1000000007>
struct ModInt {
    int data;

    ModInt(int data) : data(data) {}

    ModInt() : data(0) {}

    inline ModInt<M> operator+(ModInt<M> const &right) const {
        int temp = data + right.data;
        return ModInt(temp > M ? temp - M : temp);
    }

    inline ModInt<M> &operator+=(ModInt<M> const &right) {
        data += right.data;
        data = data > M ? data - M : data;
        return *this;
    }

    inline ModInt<M> operator-(ModInt<M> const &right) const {
        int temp = data - right.data;
        return ModInt(temp < 0 ? temp + M : temp);
    }

    inline ModInt<M> &operator-=(ModInt<M> const &right) {
        data -= right.data;
        data = data < 0 ? data + M : data;
        return *this;
    }

    inline ModInt<M> operator*(ModInt<M> const &right) const {
        int temp = data * right.data % M;
        return ModInt(temp < 0 ? temp + M : temp);
    }

    inline ModInt<M> &operator*=(ModInt<M> const &right) {
        data = data * right.data % M;
        data = data < 0 ? data + M : data;
        return *this;
    }

    inline bool operator==(ModInt<M> const &right) const {
        return data == right.data;
    }

    inline bool operator!=(ModInt<M> const &right) const {
        return data != right.data;
    }


};

template<int M = 1000000007>
inline ostream &operator<<(ostream &os, const ModInt<M> mi) {
    os << mi.data;
    return os;
}

const int MAX_LENGTH = 500500;
ModInt<1000000103> powMemo[MAX_LENGTH];
ModInt<1100000203> powMemo2[MAX_LENGTH];

void preCalc() {
    powMemo[0] = 1;
    powMemo2[0] = 1;
    for (int i = 1; i < MAX_LENGTH; ++i) {
        powMemo[i] = powMemo[i - 1] * 27;
        powMemo2[i] = powMemo2[i - 1] * 27;
    }
}

ModInt<1000000103> Slice(vector<ModInt<1000000103>> const &hash, int begin, int length) {
    return hash[begin + length] - hash[begin] * powMemo[length];
}

vector<ModInt<1000000103>> createHash(string s) {
    vector<ModInt<1000000103>> hash(s.length() + 1);
    rep(i, s.length()) {
        hash[i + 1] = hash[i] * 27 + (s[i] - 96);
    }
    return hash;
}


ModInt<1100000203> Slice(vector<ModInt<1100000203>> const &hash, int begin, int length) {
    return hash[begin + length] - hash[begin] * powMemo2[length];
}

vector<ModInt<1100000203>> createHash2(string s) {
    vector<ModInt<1100000203>> hash(s.length() + 1);
    rep(i, s.length()) {
        hash[i + 1] = hash[i] * 27 + (s[i] - 96);
    }
    return hash;
}

int N;
string S;
vector<ModInt<1000000103>> shash;
vector<ModInt<1100000203>> shash2;

signed main() {
    preCalc();
    cin >> N;
    cin >> S;
    shash = createHash(S);
    shash2 = createHash2(S);

    int can = 0, cant = N / 2 + 1;
    while (cant - can > 1) {
        int m = (can + cant) / 2;
        for (int l1 = 0; l1 + 2 * m <= N; ++l1) {
            for (int l2 = l1 + m; l2 + m <= N; ++l2) {
                if (Slice(shash, l1, m) == Slice(shash, l2, m)) {
                    if (Slice(shash2, l1, m) == Slice(shash2, l2, m)) {
                        can = m;
                        goto endwhile;
                    }
                }
            }
        }
        cant = m;
        endwhile:;
    }
    cout << can << endl;
    return 0;
}


Measured memory_bytes: 8320