#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
#include <functional>
#include <vector>
#include <queue>
#include <deque>
#include <map>
#include <set>
#include <cassert>

#define Inf 1000000000
#define nmax_def 110000
#define mod 1000000007LL
#define HASH2 999999937LL
#define HASH1 999999929LL
//#define HASH1 10LL
#define HASH3 999999893LL
/*
999999883
999999797
999999761
999999757
999999751
999999739
999999733
999999677
*/
#define rep(i,n) for(int (i)=0;(i)<(n);(i)++)
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<bool> vb;

class Rolling_hash {
private:
    vl pow_;
    vl pow_ini();
    ll pow1(ll b);

public:
    ll HASH = HASH1;
    int AN, BN;
    vl hash_A;
    vl hash_B;
    vl hash_sum_A;
    vl hash_sum_B;
    vl pow_HASH_inv;
    void h_ini_from_array(vl A, vl B);
    void h_ini_from_string(string A, string B);
    ll hash_val_A(int Ai, int len);
    ll hash_val_B(int Bi, int len);
    bool same(int Ai, int Bi, int len);
};

vl Rolling_hash::pow_ini() {
    vl pow_;
    pow_.clear();
    pow_.push_back(HASH);
    rep(j, 62) {
        ll nxt = pow_[j] * pow_[j];
        nxt %= mod;
        pow_.push_back(nxt);
    }
    return pow_;
}

ll Rolling_hash::pow1(ll b) {
    ll ans = 1;
    rep(n, 62) {
        if ((b >> (ll)n) % 2LL == 1LL) {
            ans *= pow_[n];
            ans %= mod;
        }
    }
    return ans;
}

void Rolling_hash::h_ini_from_array(vl A, vl B) {
    AN = A.size();
    BN = B.size();
    hash_A.resize(AN);
    hash_B.resize(BN);
    hash_sum_A.resize(AN + 1);
    hash_sum_B.resize(BN + 1);
    hash_sum_A[0] = 0;
    hash_sum_B[0] = 0;

    ll hashtmp = 1;
    rep(i, AN) {
        hash_A[i] = A[i] * hashtmp;
        hash_A[i] %= mod;
        hash_sum_A[i + 1] = hash_sum_A[i] + hash_A[i];
        hash_sum_A[i + 1] %= mod;
        hashtmp *= HASH;
        hashtmp %= mod;
    }
    hashtmp = 1;
    rep(i, BN) {
        hash_B[i] = B[i] * hashtmp;
        hash_B[i] %= mod;
        hash_sum_B[i + 1] = hash_sum_B[i] + hash_B[i];
        hash_sum_B[i + 1] %= mod;
        hashtmp *= HASH;
        hashtmp %= mod;
    }

    pow_ = pow_ini();
    int powN = max(AN, BN);
    pow_HASH_inv.resize(powN);
    pow_HASH_inv[powN - 1] = pow1(mod - (ll)powN);
    for (int i = powN - 2; i >= 0; i--) {
        pow_HASH_inv[i] = pow_HASH_inv[i + 1] * HASH;
        //cout << i << " A " << pow_HASH_inv[i] << endl;
        pow_HASH_inv[i] %= mod;
        //cout << i << " A " << pow_HASH_inv[i] << endl;
    }
    return;
}

void Rolling_hash::h_ini_from_string(string A, string B) {
    AN = A.length();
    BN = B.length();
    vl Avec(AN);
    vl Bvec(BN);
    rep(i, AN) {
        Avec[i] = (ll)A[i] - (ll)'a' + 1;
    }
    rep(i, BN) {
        Bvec[i] = (ll)B[i] - (ll)'a' + 1;
    }
    h_ini_from_array(Avec, Bvec);
    return;
}

ll Rolling_hash::hash_val_A(int Ai, int len) { // i文字目からlen文字
    ll hash_tmp = hash_sum_A[Ai + len] - hash_sum_A[Ai];
    hash_tmp += mod;
    hash_tmp *= pow_HASH_inv[Ai];
    if (pow_HASH_inv[Ai] <= 0) {
        cout << pow_HASH_inv[Ai] << " ERROR " << Ai << endl;
    }
    hash_tmp %= mod;
    return hash_tmp;
}

ll Rolling_hash::hash_val_B(int Bi, int len) { // i文字目からlen文字
    ll hash_tmp = hash_sum_B[Bi + len] - hash_sum_B[Bi];
    hash_tmp += mod;
    hash_tmp *= pow_HASH_inv[Bi];
    hash_tmp %= mod;
    return hash_tmp;
}

bool Rolling_hash::same(int Ai, int Bi, int len) {
    return (hash_val_A(Ai, len) == hash_val_B(Bi, len));
}

int main() {
    int N;
    string S;
    cin >> N;
    cin >> S;
    int L = 0;
    int R = N;
    Rolling_hash hashlist1, hashlist2, hashlist3;
    hashlist1.HASH = HASH1;
    hashlist2.HASH = HASH2;
    hashlist3.HASH = HASH3;
    hashlist1.h_ini_from_string(S, S);
    hashlist2.h_ini_from_string(S, S);
    hashlist3.h_ini_from_string(S, S);
    while (1) {
        int M = (L + R) / 2;
        if (L == M)
            break;
        map<ll, int> hash_i_1, hash_i_2, hash_i_3;
        bool ansfind = false;
        rep(i, N - M + 1) {
            ll hash_tmp1 = hashlist1.hash_val_A(i, M);
            ll hash_tmp2 = hashlist2.hash_val_A(i, M);
            ll hash_tmp3 = hashlist3.hash_val_A(i, M);
            
            if (hash_tmp1 < 0)
                assert(false); // RE
            if (hash_tmp2 < 0)
                assert(false); // RE
            if (hash_tmp3 < 0)
                assert(false); // RE
                
            //cout << i << " " << M << " " << hash_tmp << endl;
            bool hash_new = false;
            if (hash_i_1.find(hash_tmp1) != hash_i_1.end()) {
                bool hashcheck = true;
                if (hash_i_2.find(hash_tmp2) == hash_i_2.end()) {
                    hashcheck = false;
                   //assert(false); // RE
                }
                if (hash_i_3.find(hash_tmp3) == hash_i_3.end()) {
                    hashcheck = false;
                    //assert(false); // RE
                }
                if (hashcheck) {
                    if (hash_i_1[hash_tmp1] <= i - M) { // 重ならないのでOK
                        ansfind = true;
                        break;
                    }
                    else if (hash_i_2[hash_tmp2] <= i - M) { // 重ならないのでOK
                        ansfind = true;
                        break;
                    }
                    else if (hash_i_3[hash_tmp3] <= i - M) { // 重ならないのでOK
                        ansfind = true;
                        break;
                    }
                    // 重なるなら今後の候補にもならない
                }
                else { // 衝突
                    hash_new = true;
                }
            }
            else {
                hash_new = true;
            }
            if(hash_new){
                hash_i_1[hash_tmp1] = i;
                hash_i_2[hash_tmp2] = i;
                hash_i_3[hash_tmp3] = i;
            }
        }
        if (ansfind)
            L = M;
        else
            R = M;
    }
    cout << L << endl;
    return 0;
}

Measured memory_bytes: 1792