import sys,collections as cl,bisect as bs,heapq as hq

input = sys.stdin.readline

def l(): #intのlist

    return list(map(int,input().split()))

def m(): #複数文字

    return list(map(int,input().split()))

def onem(): #Nとかの取得

    return int(eval(input()))

def jo(x): #listをスペースごとに分ける

    return " ".join(map(str,x))

def In(x,a): #aがリスト(sorted)

    k = bs.bisect_left(a,x)

    if k != len(a) and a[k] ==  x:

        return True

    else:

        return False



def search(a,n):

    se = dict()

    data = []

    for i in range(0,len(a)-n+1):

        kkk = a[i:i+n]

        kkk = "".join(kkk)

        if In(kkk,data):

            if se[kkk] <= i-n:

                    return True

        else:

            bs.insort(data,kkk)

            se[kkk] = i

    return False

def solver():

    n = onem()



    s = list(eval(input()))

    l = 0

    r = n//2

    for i in range(n):

        mid = -(-(l+r)//2)

        ans = search(s,mid)

        if l == mid:

            break

        if ans:

            l = mid

        else:

            r = mid-1

    print(l)







if __name__ == '__main__':

    solver()







import sys,collections as cl,bisect as bs , heapq as hq

sys.setrecursionlimit(100000)

mod = 10**9+7

Max = sys.maxsize

def l(): #intのlist

    return list(map(int,input().split()))

def m(): #複数文字

    return list(map(int,input().split()))

def onem(): #Nとかの取得

    return int(eval(input()))

def s(x): #圧縮

    a = []

    aa = x[0]

    su = 1

    for i in range(len(x)-1):

        if aa != x[i+1]:

            a.append([aa,su])

            aa = x[i+1]

            su = 1

        else:

            su += 1

    a.append([aa,su])

    return a

def jo(x): #listをスペースごとに分ける

    return " ".join(map(str,x))

def max2(x): #他のときもどうように作成可能

    return max(list(map(max,x)))

def In(x,a): #aがリスト(sorted)

    k = bs.bisect_left(a,x)

    if k != len(a) and a[k][0] ==  x:

        return True

    else:

        return False



def search(a,n):

    se = dict()

    for i in range(0,len(a)-n+1):

        kkk = a[i:i+n]

        kkk = "".join(kkk)

        if kkk in se:

            if se[kkk] <= i-n:

                    return True

        else:

            se[kkk] = i

    return False





n = onem()



s = list(eval(input()))

l = 0

r = n//2

while True:

    mid = -(-(l+r)//2)

    ans = search(s,mid)

    if l == mid:

        break

    if ans:

        l = mid

    else:

        r = mid-1

print(l)

import sys, collections as cl, bisect as bs, heapq as hq

input = sys.stdin.readline


def l():  # intのlist
    return list(map(int, input().split()))


def m():  # 複数文字
    return list(map(int, input().split()))


def onem():  # Nとかの取得
    return int(eval(input()))


def jo(x):  # listをスペースごとに分ける
    return " ".join(map(str, x))


def In(x, a):  # aがリスト(sorted)
    k = bs.bisect_left(a, x)
    if k != len(a) and a[k] == x:
        return True
    else:
        return False


def search(a, n):
    se = dict()
    data = []
    for i in range(0, len(a) - n + 1):
        kkk = a[i : i + n]
        kkk = "".join(kkk)
        if In(kkk, data):
            if se[kkk] <= i - n:
                return True
        else:
            bs.insort(data, kkk)
            se[kkk] = i
    return False


def solver():
    n = onem()
    s = list(eval(input()))
    l = 0
    r = n // 2
    for i in range(n):
        mid = -(-(l + r) // 2)
        ans = search(s, mid)
        if l == mid:
            break
        if ans:
            l = mid
        else:
            r = mid - 1
    print(l)


if __name__ == "__main__":
    solver()

import sys, collections as cl, bisect as bs, heapq as hq

sys.setrecursionlimit(100000)
mod = 10**9 + 7
Max = sys.maxsize


def l():  # intのlist
    return list(map(int, input().split()))


def m():  # 複数文字
    return list(map(int, input().split()))


def onem():  # Nとかの取得
    return int(eval(input()))


def s(x):  # 圧縮
    a = []
    aa = x[0]
    su = 1
    for i in range(len(x) - 1):
        if aa != x[i + 1]:
            a.append([aa, su])
            aa = x[i + 1]
            su = 1
        else:
            su += 1
    a.append([aa, su])
    return a


def jo(x):  # listをスペースごとに分ける
    return " ".join(map(str, x))


def max2(x):  # 他のときもどうように作成可能
    return max(list(map(max, x)))


def In(x, a):  # aがリスト(sorted)
    k = bs.bisect_left(a, x)
    if k != len(a) and a[k][0] == x:
        return True
    else:
        return False


def search(a, n):
    se = dict()
    for i in range(0, len(a) - n + 1):
        kkk = a[i : i + n]
        kkk = "".join(kkk)
        if kkk in se:
            if se[kkk] <= i - n:
                return True
        else:
            se[kkk] = i
    return False


n = onem()
s = list(eval(input()))
l = 0
r = n // 2
while True:
    mid = -(-(l + r) // 2)
    ans = search(s, mid)
    if l == mid:
        break
    if ans:
        l = mid
    else:
        r = mid - 1
print(l)

-input = sys.stdin.readline +sys.setrecursionlimit(100000) +mod = 10**9 + 7 +Max = sys.maxsize +def s(x):  # 圧縮 +    a = [] +    aa = x[0] +    su = 1 +    for i in range(len(x) - 1): +        if aa != x[i + 1]: +            a.append([aa, su]) +            aa = x[i + 1] +            su = 1 +        else: +            su += 1 +    a.append([aa, su]) +    return a + + +def max2(x):  # 他のときもどうように作成可能 +    return max(list(map(max, x))) + + -    if k != len(a) and a[k] == x: +    if k != len(a) and a[k][0] == x: -    data = [] -        if In(kkk, data): +        if kkk in se: -            bs.insort(data, kkk) -def solver(): -    n = onem() -    s = list(eval(input())) -    l = 0 -    r = n // 2 -    for i in range(n): -        mid = -(-(l + r) // 2) -        ans = search(s, mid) -        if l == mid: -            break -        if ans: -            l = mid -        else: -            r = mid - 1 -    print(l) - - -if __name__ == "__main__": -    solver() +n = onem() +s = list(eval(input())) +l = 0 +r = n // 2 +while True: +    mid = -(-(l + r) // 2) +    ans = search(s, mid) +    if l == mid: +        break +    if ans: +        l = mid +    else: +        r = mid - 1 +print(l)