# suffix array

# z-algorithm

# rolling-hash

# dp

n = int(eval(input()))

s = eval(input())



# z-algorithm

# i左端

# j iからの距離

# k i-i+jの間を進みながら比較

ans = 0

for num in range(n - 1):

    S = s[num:]

    A = [0] * (n - num)

    A[0] = n - num

    i = 1

    j = 0

    while i < n - num:

        while i + j < n - num and S[j] == S[i + j]:

            j += 1

        A[i] = j

        ans = max(ans, min(i, j))

        if j == 0:

            i += 1

            continue

        k = 1

        while i + k < n - num and k + A[k] < j:

            A[i + k] = A[k]

            ans = max(ans, min(k, A[k]))

            k += 1

        i += k

        j -= k

print(ans)

# 32bitのMod一つでRollingHashを行った場合、

# 10**5個程度のHashを生成するだけでも

# 半分以上の確率でどこかのHashが衝突していることが分かります





# 小文字アルファベットの時のbese

base = 27  # alphabet





def getnum(x):

    return ord(x) - ord("a") + 1





# rolling hash実装



# 必要な定数

# mod = 1<<61-1としたときの高速余り計算

m30 = (1 << 30) - 1

m31 = (1 << 31) - 1

m61 = (1 << 61) - 1

mod = m61

positive_delta = m61 ** 4



# 高速化された計算

def mul(a, b):

    au = a >> 31

    ad = a & m31  # 余りを取ることが&演算でできる

    bu = b >> 31

    bd = b & m31

    mid = ad * bu + au * bd

    midu = mid >> 30

    midd = mid & m30

    return calcmod(au * bu * 2 + midu + (midd << 31) + ad * bd)





def calcmod(a):

    au = a >> 61

    ad = a & m61

    res = au + ad

    if res >= m61:

        res -= m61

    return res





# s:string

def rollinghash(s):

    num = len(s)

    res = [0] * (num + 1)

    pow_base = [1] * (num + 1)

    for i in range(num):

        res[i + 1] = calcmod(mul(res[i], base) + getnum(s[i]))

        pow_base[i + 1] = calcmod(mul(pow_base[i], base))

    return res, pow_base





def search(left, right, rh):

    return calcmod(rh[right] - mul(rh[left], pow_base[right - left]) + positive_delta)





n = int(eval(input()))

s = eval(input())

rh, pow_base = rollinghash(s)



ng = n

ok = 0





def hantei(x, rh):

    kumi = {}

    for i in range(n - x + 1):

        temp = search(i, i + x, rh)

        if temp in kumi:

            pre_idx = kumi[temp]

            if i - pre_idx >= x:

                # print("pair", i, pre_idx, "delta", x)

                return True

        else:

            kumi[temp] = i

    # print(x, kumi)

    return False





while ng - ok > 1:

    mid = (ng + ok) // 2

    if hantei(mid, rh):

        ok = mid

    else:

        ng = mid

    # print(ok, ng)



print(ok)

# suffix array
# z-algorithm
# rolling-hash
# dp
n = int(eval(input()))
s = eval(input())
# z-algorithm
# i左端
# j iからの距離
# k i-i+jの間を進みながら比較
ans = 0
for num in range(n - 1):
    S = s[num:]
    A = [0] * (n - num)
    A[0] = n - num
    i = 1
    j = 0
    while i < n - num:
        while i + j < n - num and S[j] == S[i + j]:
            j += 1
        A[i] = j
        ans = max(ans, min(i, j))
        if j == 0:
            i += 1
            continue
        k = 1
        while i + k < n - num and k + A[k] < j:
            A[i + k] = A[k]
            ans = max(ans, min(k, A[k]))
            k += 1
        i += k
        j -= k
print(ans)

# 32bitのMod一つでRollingHashを行った場合、
# 10**5個程度のHashを生成するだけでも
# 半分以上の確率でどこかのHashが衝突していることが分かります
# 小文字アルファベットの時のbese
base = 27  # alphabet


def getnum(x):
    return ord(x) - ord("a") + 1


# rolling hash実装
# 必要な定数
# mod = 1<<61-1としたときの高速余り計算
m30 = (1 << 30) - 1
m31 = (1 << 31) - 1
m61 = (1 << 61) - 1
mod = m61
positive_delta = m61**4
# 高速化された計算
def mul(a, b):
    au = a >> 31
    ad = a & m31  # 余りを取ることが&演算でできる
    bu = b >> 31
    bd = b & m31
    mid = ad * bu + au * bd
    midu = mid >> 30
    midd = mid & m30
    return calcmod(au * bu * 2 + midu + (midd << 31) + ad * bd)


def calcmod(a):
    au = a >> 61
    ad = a & m61
    res = au + ad
    if res >= m61:
        res -= m61
    return res


# s:string
def rollinghash(s):
    num = len(s)
    res = [0] * (num + 1)
    pow_base = [1] * (num + 1)
    for i in range(num):
        res[i + 1] = calcmod(mul(res[i], base) + getnum(s[i]))
        pow_base[i + 1] = calcmod(mul(pow_base[i], base))
    return res, pow_base


def search(left, right, rh):
    return calcmod(rh[right] - mul(rh[left], pow_base[right - left]) + positive_delta)


n = int(eval(input()))
s = eval(input())
rh, pow_base = rollinghash(s)
ng = n
ok = 0


def hantei(x, rh):
    kumi = {}
    for i in range(n - x + 1):
        temp = search(i, i + x, rh)
        if temp in kumi:
            pre_idx = kumi[temp]
            if i - pre_idx >= x:
                # print("pair", i, pre_idx, "delta", x)
                return True
        else:
            kumi[temp] = i
    # print(x, kumi)
    return False


while ng - ok > 1:
    mid = (ng + ok) // 2
    if hantei(mid, rh):
        ok = mid
    else:
        ng = mid
    # print(ok, ng)
print(ok)

-# suffix array -# z-algorithm -# rolling-hash -# dp +# 32bitのMod一つでRollingHashを行った場合、 +# 10**5個程度のHashを生成するだけでも +# 半分以上の確率でどこかのHashが衝突していることが分かります +# 小文字アルファベットの時のbese +base = 27  # alphabet + + +def getnum(x): +    return ord(x) - ord("a") + 1 + + +# rolling hash実装 +# 必要な定数 +# mod = 1<<61-1としたときの高速余り計算 +m30 = (1 << 30) - 1 +m31 = (1 << 31) - 1 +m61 = (1 << 61) - 1 +mod = m61 +positive_delta = m61**4 +# 高速化された計算 +def mul(a, b): +    au = a >> 31 +    ad = a & m31  # 余りを取ることが&演算でできる +    bu = b >> 31 +    bd = b & m31 +    mid = ad * bu + au * bd +    midu = mid >> 30 +    midd = mid & m30 +    return calcmod(au * bu * 2 + midu + (midd << 31) + ad * bd) + + +def calcmod(a): +    au = a >> 61 +    ad = a & m61 +    res = au + ad +    if res >= m61: +        res -= m61 +    return res + + +# s:string +def rollinghash(s): +    num = len(s) +    res = [0] * (num + 1) +    pow_base = [1] * (num + 1) +    for i in range(num): +        res[i + 1] = calcmod(mul(res[i], base) + getnum(s[i])) +        pow_base[i + 1] = calcmod(mul(pow_base[i], base)) +    return res, pow_base + + +def search(left, right, rh): +    return calcmod(rh[right] - mul(rh[left], pow_base[right - left]) + positive_delta) + + -# z-algorithm -# i左端 -# j iからの距離 -# k i-i+jの間を進みながら比較 -ans = 0 -for num in range(n - 1): -    S = s[num:] -    A = [0] * (n - num) -    A[0] = n - num -    i = 1 -    j = 0 -    while i < n - num: -        while i + j < n - num and S[j] == S[i + j]: -            j += 1 -        A[i] = j -        ans = max(ans, min(i, j)) -        if j == 0: -            i += 1 -            continue -        k = 1 -        while i + k < n - num and k + A[k] < j: -            A[i + k] = A[k] -            ans = max(ans, min(k, A[k])) -            k += 1 -        i += k -        j -= k -print(ans) +rh, pow_base = rollinghash(s) +ng = n +ok = 0 + + +def hantei(x, rh): +    kumi = {} +    for i in range(n - x + 1): +        temp = search(i, i + x, rh) +        if temp in kumi: +            pre_idx = kumi[temp] +            if i - pre_idx >= x: +                # print("pair", i, pre_idx, "delta", x) +                return True +        else: +            kumi[temp] = i +    # print(x, kumi) +    return False + + +while ng - ok > 1: +    mid = (ng + ok) // 2 +    if hantei(mid, rh): +        ok = mid +    else: +        ng = mid +    # print(ok, ng) +print(ok)