#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

#define ll long long int
#define pb push_back
#define eb emplace_back
#define xx first
#define yy second
#define INF 0x3f3f3f3f

using namespace std;
using namespace __gnu_pbds;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
typedef tree<int,null_type, less<int>,rb_tree_tag,tree_order_statistics_node_update>   ordered_set;
const int N=1e6+1, mod= 998244353;

struct suffix 
{ 
	int index; // To store original index 
	int rank[2]; // To store ranks and next rank pair 
}; 


int cmp(struct suffix a, struct suffix b) 
{ 
	return (a.rank[0] == b.rank[0])? (a.rank[1] < b.rank[1] ?1: 0): 
		(a.rank[0] < b.rank[0] ?1: 0); 
} 

vector<int> buildSuffixArray(string txt, int n) { 
	// A structure to store suffixes and their indexes 
	struct suffix suffixes[n]; 

	for (int i = 0; i < n; i++) { 
		suffixes[i].index = i; 
		suffixes[i].rank[0] = txt[i] - 'a'; 
		suffixes[i].rank[1] = ((i+1) < n)? (txt[i + 1] - 'a'): -1; 
	} 

	sort(suffixes, suffixes+n, cmp); 

	int ind[n]; 
	for (int k = 4; k < 2*n; k = k*2) { 
		// Assigning rank and index values to first suffix 
		int rank = 0; 
		int prev_rank = suffixes[0].rank[0]; 
		suffixes[0].rank[0] = rank; 
		ind[suffixes[0].index] = 0; 

		// Assigning rank to suffixes 
		for (int i = 1; i < n; i++) 
		{ 
			if (suffixes[i].rank[0] == prev_rank && 
					suffixes[i].rank[1] == suffixes[i-1].rank[1]) 
			{ 
				prev_rank = suffixes[i].rank[0]; 
				suffixes[i].rank[0] = rank; 
			} 
			else // Otherwise increment rank and assign 
			{ 
				prev_rank = suffixes[i].rank[0]; 
				suffixes[i].rank[0] = ++rank; 
			} 
			ind[suffixes[i].index] = i; 
		} 

		// Assign next rank to every suffix 
		for (int i = 0; i < n; i++) 
		{ 
			int nextindex = suffixes[i].index + k/2; 
			suffixes[i].rank[1] = (nextindex < n)? 
								suffixes[ind[nextindex]].rank[0]: -1; 
		} 

		sort(suffixes, suffixes+n, cmp); 
	} 

	vector<int>suffixArr; 
	for (int i = 0; i < n; i++) 
		suffixArr.push_back(suffixes[i].index); 

	return suffixArr; 
} 


vector<int> kasai(string txt, vector<int> &suffixArr) 
{
	int n = suffixArr.size();

	vector<int> lcp(n, 0);
	vector<int> invSuff(n, 0);

	for (int i=0; i < n; i++) 
		invSuff[suffixArr[i]] = i; 

	int k = 0; 

	for (int i=0; i<n; i++) 
	{ 

		if (invSuff[i] == n-1) 
		{ 
			k = 0; 
			continue; 
		} 


		int j = suffixArr[invSuff[i]+1]; 
		while (i+k<n && j+k<n && txt[i+k]==txt[j+k]) 
			k++; 

		lcp[invSuff[i]] = k; // lcp for the present suffix. 

		if (k>0) 
			k--; 
	} 
	
	return lcp; 
} 

int main(){
	ios_base::sync_with_stdio(0);	cin.tie(0);
	int n,res=0; string s;
	cin>>n>>s;
	vector<int>suffixArr = buildSuffixArray(s,n);
	vector<int>lcp = kasai(s, suffixArr);
	
	int mn[n][n];
	memset(mn,INF,sizeof mn);
	for(int i=0;i<n;i++)for(int j=0;j<n;j++){
		if(i==j)mn[i][j]=lcp[i];
		else mn[i][j]=min(lcp[j],mn[i][j-1]);
	}
	
	for(int i=0;i<n-1; ){
		int j=i;
		while( j<n && lcp[j]!=0 )j++;
		
		for(int k=i;k<j;k++ ){
			for(int l=k+1;l<=j;l++){
				if( abs(suffixArr[k]-suffixArr[l])>= mn[k][l-1] ){
					res=max(res, mn[k][l-1] );
				}
			}
		}
		
		i=j+1;
	}
	cout<<res;
}
/*
18
prqrdllluscohgbfwg
 */


Measured memory_bytes: 98048