#pragma GCC optimize ("O3")
#pragma GCC target ("sse4")
 
#include <bits/stdc++.h>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
 
using namespace std;
using namespace __gnu_pbds;
 
typedef long long ll;
typedef long double ld;
typedef complex<ld> cd;
 
typedef pair<int, int> pi;
typedef pair<ll,ll> pl;
typedef pair<ld,ld> pd;
 
typedef vector<int> vi;
typedef vector<ld> vd;
typedef vector<ll> vl;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<cd> vcd;
 
template <class T> using Tree = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>;
 
#define FOR(i, a, b) for (int i=a; i<(b); i++)
#define F0R(i, a) for (int i=0; i<(a); i++)
#define FORd(i,a,b) for (int i = (b)-1; i >= a; i--)
#define F0Rd(i,a) for (int i = (a)-1; i >= 0; i--)
 
#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define f first
#define s second
#define lb lower_bound
#define ub upper_bound
#define all(x) x.begin(), x.end()
 
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
 
const int MOD = 1000000007;
const ll INF = 1e18;
const int MX = 5001; //check the limits, dummy

struct hsh  {
    ll base, p1, p2;
   
    ll val1, val2;
   
    ll inv1, inv2;
   
    ll modExp(ll power, ll prime) {
        if (power == 0) {
            return 1;
        } else {
            ll cur = modExp(power / 2, prime); cur = cur * cur; cur = cur % prime;
            if (power % 2 == 1) cur = cur * base;
            cur = cur % prime;
            return cur;
        }
    }
   
    hsh() {
    }
   
    hsh(ll b, ll x, ll y) {
        base = b;
        p1 = x;
        p2 = y;
        val1 = 0;
        val2 = 0;
       
        //inv2 = modExp(p2-2, p2);
        //inv1 = modExp(p1-2, p1);
    }
   
    hsh(ll b) {
        p1 = 1000000007;
        p2 = 1000000009;
        base = b;
        val1 = 0;
        val2 = 0;
       
        //inv2 = modExp(p2-2, p2);
        //inv1 = modExp(p1-2, p1);
    }
   
    hsh(ll b, string S) {
        p1 = 1000000007;
        p2 = 1000000009;
        base = b;
        val1 = 0;
        val2 = 0;
       
        //inv2 = modExp(p2-2, p2);
        //inv1 = modExp(p1-2, p1);
        F0R(i, sz(S)) {
            push_back(S[i] - 'a');
        }
    }
   
    void push_back(ll v) {
        val1 *= base;
        val1 %= p1;
        val1 += v;
        val1 %= p1;
        val2 *= base;
        val2 %= p2;
        val2 += v;
        val2 %= p2;
       

    }

   
  
    bool operator==(const hsh &v) const {
        return (val1 == v.val1 && val2 == v.val2 );
    }
   
    bool operator<(const hsh &v) const {
        if (val1 == v.val1) {
            return val2 < v.val2;
        }
        return val1 < v.val1;
    }
   
};

vector<vector<hsh> > all;

bool valid(int N, string S, int L) {
	if (L == 0) return true;
	
	
	
	hsh hashes[N-L+1];
	
	F0R(start, N-L+1) {
		hashes[start] = all[start][L];
	}
	
	set<hsh> hshSet;
	
	F0R(i, N-L+1) {
		if (i >= L) {
			hshSet.insert(hashes[i-L]);
		}
		
		if (hshSet.count(hashes[i])) return true;
	}
	
	return false;
	
}
 
int main() {
	ios_base::sync_with_stdio(0); cin.tie(0);    
	
	int N; cin >> N;
	
	string S; cin >> S;
	
	int base = uniform_int_distribution<int>(1000, MOD-2)(rng);
	F0R(i, N) {
		vector<hsh> curAll;
		curAll.pb(hsh(base));
		FOR(j, i, N) {
			hsh cur = curAll[j-i];
			cur.push_back(S[j]);
			curAll.pb(cur);
		}
		all.pb(curAll);
	}
	
	int lo = 0;
	int hi = N;
	
	F0R(i, 13) {
		int mid = (lo+hi)/2;
		if (valid(N, S, mid)) {
			lo = mid;
		} else {
			hi = mid-1;
		}
	}
	
	if (valid(N, S, max(lo, hi))) {
		cout << max(lo, hi) << endl;
	} else {
		cout << min(lo, hi) << endl;
	}
	
	
	
	
	return 0;
}
 
// read the question correctly (ll vs int)
// template by bqi343


Measured memory_bytes: 685224