#include<bits/stdc++.h>
using namespace std;

void __print(int x) {cerr << x;}
void __print(long x) {cerr << x;}
void __print(long long x) {cerr << x;}
void __print(unsigned x) {cerr << x;}
void __print(unsigned long x) {cerr << x;}
void __print(unsigned long long x) {cerr << x;}
void __print(float x) {cerr << x;}
void __print(double x) {cerr << x;}
void __print(long double x) {cerr << x;}
void __print(char x) {cerr << '\'' << x << '\'';}
void __print(const char *x) {cerr << '\"' << x << '\"';}
void __print(const string &x) {cerr << '\"' << x << '\"';}
void __print(bool x) {cerr << (x ? "true" : "false");}

template<typename T, typename V>
void __print(const pair<T, V> &x) {cerr << '{'; __print(x.first); cerr << ','; __print(x.second); cerr << '}';}
template<typename T>
void __print(const T &x) {int f = 0; cerr << '{'; for (auto &i: x) cerr << (f++ ? "," : ""), __print(i); cerr << "}";}
void _print() {cerr << "]\n";}
template <typename T, typename... V>
void _print(T t, V... v) {__print(t); if (sizeof...(v)) cerr << ", "; _print(v...);}

#ifndef ONLINE_JUDGE
#define debug(x...) cerr << "[" << #x << "] = ["; _print(x)
#else
#define debug(x...)
#endif

#define REP(i, n) for(int i = 0; i < (n); i++)
#define FOR(i, a, b) for(int i = (a); i <= (b); i++)
#define FORD(i, a, b) for(int i = (a); i >= (b); i--)
#define A first
#define B second
#define MD 1000000007

typedef pair<int,int> ii;
typedef vector<ii> vii;
typedef long long ll;

int mulmd(ll a, ll b){
    ll ret = (a * b) % MD;
    return (int)ret;
}

inline int power(ll x, ll y, int p)
{
    ll res = 1;
    x = x % p;
    while (y > 0)
    {
        if (y & 1)
            res = mulmd(res, x);
        y = y >> 1;
        x = mulmd(x, x);
    }
    return (int)res;
}

int submd(ll a, ll b){
    ll ret = a - b;
    if(ret < 0){
        ret += MD;
    }
    return (int)ret;
}

int addmd(ll a, ll b){
    ll ret = (a + b) % MD;
    return (int)ret;
}

int invPow(ll a){
    return power(a, MD - 2, MD);
}

const int N = 1e5 + 5;

int arr[N];
string s;
int n;

// Credit: https://github.com/Ashishgup1/Competitive-Coding/blob/master/Hashing%20(Strings).cpp
struct Hashs
{
	vector<int> hashs;
	vector<int> pows;
	int P;
	int MOD;

	Hashs() {}

	Hashs(string &s, int P, int MOD) : P(P), MOD(MOD)
	{
		int n = s.size();
		pows.resize(n+1, 0);
		hashs.resize(n+1, 0);
		pows[0] = 1;
		for(int i=n-1;i>=0;i--)
		{
			hashs[i] = (1LL * hashs[i+1] * P + s[i] - 'a' + 1) % MOD;
			pows[n-i] = (1LL * pows[n-i-1] * P) % MOD;
		}
		pows[n] = (1LL * pows[n-1] * P)%MOD;
	}
	int get_hash(int l, int r)
	{
		int ans = hashs[l] + MOD - (1LL*hashs[r+1]*pows[r-l+1])%MOD;
		ans %= MOD;
		return ans;
	}
};
Hashs hs;

bool check(int len){
    for(int i = 0; i <= n - len + 1; i++){
        int h = hs.get_hash(i, i + len - 1);
        for(int j = i + len; j <= n - len + 1; j++){
            if(j + len - 1 >= n) break;
            int r = hs.get_hash(j, j + len - 1);
            if(h == r) return true;
        }
    }
    return false;
}


int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cin >> n;
    cin >> s;
    hs = Hashs(s, 31, MD);
    int l = 0;
    int r = n/2;
    int ans = 0;
    while(l <= r){
        int md = (l + r)/2;
        if(check(md)){
            ans = md;
            l = md + 1;
        }
        else {
            r = md - 1;
        }
    }
    cout << ans;

}

/**
    Check out for boundary cases, (n = 1 or n = 0)
    check for integer overflow

**/



Measured memory_bytes: 256