### BUGGY CODE ###

import sys
input = sys.stdin.readline
import random


class RollingHash():

    def __init__(self, S, b=-1, m=10**9+7):
        if b < 0:
            b = random.randint(2, m-1)
        self.rh = self.make_hash(S, m, b)
        self.S = S
        self.m = m
        self.b = b
    
    def encode(self, c):
        return ord(c) - ord("a") + 1
    
    def make_hash(self, S, m, b):
        h = 0
        for s in S:
            h *= b
            h %= m
            c = self.encode(s)
            h += c
            h %= m
        return h

    def match(self, T):
        ns = len(self.S)
        nt = len(T)
        rh = self.make_hash(T[:ns], self.m, self.b)
        b_ns = pow(self.b, ns, self.m)

        i = 0
        while i < nt - ns:
            if rh == self.rh:
                yield i
            rh = rh * self.b + self.encode(T[i+ns]) - self.encode(T[i]) * b_ns
            rh %= self.m
            i += 1
        if rh == self.rh:
            yield i

    def find_lcp(self, T):
        ns = len(self.S)
        nt = len(T)
        rh = self.make_hash(T[:ns], self.m, self.b)
        b_ns = pow(self.b, ns, self.m)
        b_inv = pow(self.b, self.m-2, self.m)

        i = 0
        while i < nt - ns:
            sh = self.rh
            th = rh
            j = ns-1
            while j >= 0:
                if sh == th:
                    yield (i, j+1)
                    break
                sh -= self.encode(self.S[j])
                sh *= b_inv
                sh %= self.m
                th -= self.encode(T[i+j])
                th *= b_inv
                th %= self.m
                j -= 1
            rh = rh * self.b + self.encode(T[i+ns]) - self.encode(T[i]) * b_ns
            rh %= self.m
            i += 1
        sh = self.rh
        th = rh
        j = ns-1
        while j >= 0:
            if sh == th:
                yield (i, j+1)
                break
            sh -= self.encode(self.S[j])
            sh *= b_inv
            sh %= self.m
            th -= self.encode(T[i+j])
            th *= b_inv
            th %= self.m
            j -= 1


def read():
    N = int(input().strip())
    S = input().strip()
    return N, S


def solve(N, S):
    max_j = 0
    for i in range(1, N):
        rh = RollingHash(S[i:])
        if i >= len(S[i:]):
            for i, j in rh.find_lcp(S[:i]):
                max_j = max(max_j, j)
    return max_j

if __name__ == "__main__":
    inputs = read()
    print("%s" % solve(*inputs))


### FIXED CODE ###

import random
from collections import defaultdict


class RollingHash():

    def __init__(self, S, b=3491, m=999999937):
        """任意の基数と法でハッシュを生成する"""
        n = len(S)
        self.prefix = prefix = [0] * (n+1)
        self.power = power = [1] * (n+1)
        self.b = b
        self.m = m
        for i in range(n):
            c = ord(S[i])
            prefix[i+1] = (prefix[i] * b + c) % m
            power[i+1] = (power[i] * b) % m
    
    def get(self, l, r):
        """S[l, r) のハッシュを求める"""
        return (self.prefix[r] - self.power[r-l] * self.prefix[l]) % self.m
    
    def concat(self, h1, h2, l2):
        """S1+S2 のハッシュを、それぞれのハッシュから求める"""
        return (self.power[l2] * h1 + h2) % self.m
    
    def lcp(self, l1, r1, l2, r2):
        """S[l1, r1) とS[l2, r2) の最大共通接頭辞を求める"""
        low = 0
        high = min(r1-l1, r2-l2) + 1
        while high - low > 1:
            mid = (high + low) // 2
            if self.get(l1, l1 + mid) == self.get(l2, l2 + mid):
                low = mid
            else:
                high = mid
        return low


def read():
    N = int(input().strip())
    S = input().strip()
    return N, S


def solve(N, S):
    ans = []
    for m in [999999937, 10**9+7]:
        b = random.randint(10000, m-1)
        rh = RollingHash(S, b=b, m=m)
        low = 0
        high = (N+1) // 2 + 1
        dmax = defaultdict(int)
        dmin = defaultdict(int)
        while high - low > 1:
            dmax.clear()
            dmin.clear()
            mid = (high + low) // 2
            for i in range(0, N-mid+1):
                h = rh.get(i, i+mid)
                dmax[h] = max(dmax[h], i+1)
                dmin[h] = max(dmin[h], N+1-i)
            is_match = False
            for h in dmax.keys():
                if dmax[h] - (N+2 - dmin[h]) >= mid:
                    is_match = True
                    break
            if is_match:
                low = mid
            else:
                high = mid
        ans.append(low)
    return min(ans)


if __name__ == '__main__':
    inputs = read()
    outputs = solve(*inputs)
    if outputs is not None:
        print("%s" % str(outputs))