// Slower C++ solution:
#include <bits/stdc++.h>

#define mp make_pair

#define ff first

#define ss second

using namespace std;

typedef long long LL;

typedef pair<LL, LL> PLL;

typedef pair<int, int> PII;

 

const PLL M = mp(1e9+7, 1e9+9);        ///Should be large primes

const LL base = 875329;               ///Should be a prime larger than highest value

const int N = 1e5+7;                 ///Highest length of string

 

ostream& operator<<(ostream& os, PLL hash) {

    return os<<"("<<hash.ff<<", "<<hash.ss<<")";

}

 

PLL operator+ (PLL a, LL x)     {return mp(a.ff + x, a.ss + x);}

PLL operator- (PLL a, LL x)     {return mp(a.ff - x, a.ss - x);}

PLL operator* (PLL a, LL x)     {return mp(a.ff * x, a.ss * x);}

PLL operator+ (PLL a, PLL x)    {return mp(a.ff + x.ff, a.ss + x.ss);}

PLL operator- (PLL a, PLL x)    {return mp(a.ff - x.ff, a.ss - x.ss);}

PLL operator* (PLL a, PLL x)    {return mp(a.ff * x.ff, a.ss * x.ss);}

PLL operator% (PLL a, PLL m)    {return mp(a.ff % m.ff, a.ss % m.ss);}

 

PLL pb[N];      ///powers of base mod M

///Call pre before everything

void pre() {

    pb[0] = mp(1,1);

    for (int i=1; i<N; i++)

        pb[i] = (pb[i-1] * base)%M;

}

 

///Calculates hashes of all prefixes of s including empty prefix

vector<PLL> hashList(string &s) {

    int n = s.size();

    vector<PLL> ans(n+1);

    ans[0] = mp(0,0);

 

    for (int i=1; i<=n; i++)

        ans[i] = (ans[i-1] * base + s[i-1])%M;

    return ans;

}

 

///Calculates hash of substring s[l..r] (1 indexed)

PLL Hash(vector<PLL> &hashlist, int l, int r) {

    int len = (r-l+1);

    return ((hashlist[r] - hashlist[l-1]*pb[len])%M+M)%M;

}

vector<PLL>hashVec;

int n; 

bool ok(int len) {



    for(int i =1 ; i+len-1 <= n ; i++ ) {

        

        PLL val1 = Hash(hashVec , i , i+len-1);

        

        for(int j = i+len ; j+len-1 <=n ; j++ ) {

            

            PLL val2 = Hash(hashVec , j , j+len-1);

            if(val1 == val2) return true;

        }

    }

    return false;

}





int main() {

    

    ios::sync_with_stdio(false);

    cin.tie(0);

    pre();

    

    

    string str;

    

    cin>>n>>str;

    

    hashVec = hashList(str);

    

    int lo = 0 , hi = n;

    int ans = 0;

    

    while(lo <= hi) {

        

        int mid = (lo+hi)/2;

        

        if(ok(mid)) {

            ans = mid;

            lo = mid+1;

        }

        else hi = mid-1;

    }

    cout<<ans<<'\n';

    return 0;

    



}

// Faster C++ solution for the same problem (measured speedup: 3.647071097393925x):
#include<cstdio>

#include<cstring>

#include<iostream>

#include<algorithm>



#define nn 10010

using namespace std;



const int bs[2]={271,233};

const int mod[2]={998244353,1000000007};



char a[nn];

int n,pw[nn][2],N,as,h[nn][2];

struct Node{int h0,h1,p;}q[nn];



bool Cmp(Node a,Node b) {return(a.h0<b.h0||a.h0==b.h0&&a.h1<b.h1||a.h0==b.h0&&a.h1==b.h1&&a.p<b.p);}

inline bool Check(int md){

    N=0;

    for (int i=1;i+md-1<=n;i++){

        int nm[2];

        for (int j=0;j<2;j++) nm[j]=(h[i+md-1][j]-h[i-1][j]+mod[j])%mod[j];

        for (int j=0;j<2;j++) nm[j]=nm[j]*1ll*pw[n-(i+md-1)][j]%mod[j];

        q[++N]=(Node){nm[0],nm[1],i};

    }

    sort(q+1,q+1+N,Cmp);

    for (int j=1,i=1;i<=N;i=j){

        for (j=i;q[i].h0==q[j].h0&&q[i].h1==q[j].h1&&j<=N;j++);

        if (q[i].p+md<=q[j-1].p) return(1);

    }

    return(0);

}



int main()

{

    scanf("%d%s",&n,a+1);

    pw[0][0]=pw[0][1]=1;

    for (int i=1;i<=n;i++)

    for (int j=0;j<2;j++) pw[i][j]=pw[i-1][j]*1ll*bs[j]%mod[j];

    for (int i=1;i<=n;i++)

    for (int j=0;j<2;j++) h[i][j]=(h[i-1][j]+a[i]*1ll*pw[i][j]%mod[j])%mod[j];



    int l=1,r=n;

    while (l<=r){

        int md=(l+r)/2;

        if (Check(md)) as=md,l=md+1;

        else r=md-1;

    }

    printf("%d\n",as);

}