#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
#include <functional>
#include <vector>
#include <queue>
#include <deque>
#include <map>
#include <set>
#include <cassert>
#define InfL 1000000000
#define InfLL 1000000000000000000LL
#define nmax_def 110000
#define HASHnum 3
#define mod 1000000007LL
#define HASH0 999999937LL
#define HASH1 999999929LL
#define HASH2 999999893LL
#define rep(i,n) for(int (i)=0;(i)<(n);(i)++)
#define rrep(i,n) for(int (i)=(n-1);(i)>=(0);(i)--)
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<bool> vb;
typedef vector<db> vd;

//int HASHnum = 3;

vi Z_algorithm(string S) {
    int N = S.length();
    vi A(N);
    A[0] = N;
    int i = 1, j = 0;
    while (i < N) {
        while (i + j < N && S[j] == S[i + j])
            j++; // �E������j��L�΂��Ă���
        A[i] = j;
        if (j == 0) {
            i++;
            continue;
        }
        int k = 1;
        while (i + k < N && k + A[k] < j) {
            A[i + k] = A[k];
            k++; // i~j�Ԃ�k�𑖂点��
        }
        i += k;
        j -= k;
    }
    return A;
}

vl HASHlist;
vector<vl> pow_;
void pow_ini() {
    pow_.resize(HASHnum);
    rep(i, HASHnum){
        pow_[i].clear();
        pow_[i].push_back(HASHlist[i]);
        rep(j, 62) {
            ll nxt = pow_[i][j] * pow_[i][j];
            nxt %= mod;
            pow_[i].push_back(nxt);
        }
    }
    return;
}

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

class Rolling_hash {
public:
    int AN, BN;
    vector<vl> hash_A;
    vector<vl> hash_B;
    vector<vl> hash_sum_A;
    vector<vl> hash_sum_B;
    vector<vl> pow_HASH_inv;
    void h_ini_from_array(vl A, vl B);
    void h_ini_from_string(string A, string B);
    vl hash_val_A(int Ai, int len);
    vl hash_val_B(int Bi, int len);
    bool same(int Ai, int Bi, int len);
};

void Rolling_hash::h_ini_from_array(vl A, vl B) {
    hash_A.resize(HASHnum);
    hash_B.resize(HASHnum);
    hash_sum_A.resize(HASHnum);
    hash_sum_B.resize(HASHnum);
    pow_HASH_inv.resize(HASHnum);
    HASHlist.resize(HASHnum);
    HASHlist[0] = HASH0;
    HASHlist[1] = HASH1;
    HASHlist[2] = HASH2;
    AN = A.size();
    BN = B.size();
    pow_ini();
    rep(i, HASHnum){
        hash_A[i].resize(AN);
        hash_B[i].resize(BN);
        hash_sum_A[i].resize(AN + 1);
        hash_sum_B[i].resize(BN + 1);
        hash_sum_A[i][0] = 0;
        hash_sum_B[i][0] = 0;

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

        int powN = max(AN, BN);
        pow_HASH_inv[i].resize(powN);
        pow_HASH_inv[i][powN - 1] = pow1(i, mod - (ll)powN);
        for (int j = powN - 2; j >= 0; j--) {
            pow_HASH_inv[i][j] = pow_HASH_inv[i][j + 1] * HASHlist[i];
            pow_HASH_inv[i][j] %= mod;
        }
    }
    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;
}

vl Rolling_hash::hash_val_A(int Ai, int len) { // i�����ڂ���len����
    vl hash_val(HASHnum);
    rep(i, HASHnum){
        ll hash_tmp = hash_sum_A[i][Ai + len] - hash_sum_A[i][Ai];
        hash_tmp += mod;
        hash_tmp *= pow_HASH_inv[i][Ai];
        hash_tmp %= mod;
        hash_val[i] = hash_tmp;
    }
    return hash_val;
}

vl Rolling_hash::hash_val_B(int Bi, int len) { // i�����ڂ���len����
    vl hash_val(HASHnum);
    rep(i, HASHnum){
        ll hash_tmp = hash_sum_B[i][Bi + len] - hash_sum_B[i][Bi];
        hash_tmp += mod;
        hash_tmp *= pow_HASH_inv[i][Bi];
        hash_tmp %= mod;
        hash_val[i] = hash_tmp;
    }
    return hash_val;
}

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 hashlist;
    hashlist.h_ini_from_string(S, S);
    while (1) {
        int M = (L + R) / 2;
        if (L == M)
            break;
        map<vl, int> hash_i;
        bool ansfind = false;
        rep(i, N - M + 1) {
            vl hash_tmp = hashlist.hash_val_A(i, M);
            if (hash_i.find(hash_tmp) != hash_i.end()) {
                if (hash_i[hash_tmp] <= i - M) {
                    ansfind = true;
                    break;
                }
            }
            else {
                hash_i[hash_tmp] = i;
            }
        }
        if (ansfind)
            L = M;
        else
            R = M;
    }
    cout << L << endl;
	return 0;
}


Measured memory_bytes: 1408