from typing import List


class RollingHash:
    """Rolling Hash"""

    __slots__ = ["_base", "_mod", "_hash", "_power"]

    def __init__(self, source: str, base: int = 1007, mod: int = 10 ** 9 + 7):
        self._base = base
        self._mod = mod
        self._hash = self._build_hash_from_zero(source)
        self._power = self._build_base_power(len(source))

    def _build_hash_from_zero(self, source: str) -> List[int]:
        """Compute hash of interval [0, right)."""
        res = [0] * (len(source) + 1)
        for i, c in enumerate(source, 1):
            res[i] = (res[i - 1] * self._base + ord(c)) % self._mod
        return res

    def _build_base_power(self, length: int) -> List[int]:
        """Compute mod of power of base."""
        res = [1] * (length + 1)
        for i in range(1, length + 1):
            res[i] = res[i - 1] * self._base % self._mod
        return res

    def get_hash(self, left: int, right: int):
        """Return hash of interval [left, right)."""
        return (
            self._hash[right] - self._hash[left] * self._power[right - left]
        ) % self._mod


def abc141_e():
    # https://atcoder.jp/contests/abc141/tasks/abc141_e
    N = int(input())
    S = input().rstrip()

    rh = RollingHash(S)
    ok, ng = 0, N // 2 + 1
    while ng - ok > 1:
        mid = (ok + ng) // 2
        flg = False
        memo = set()
        for i in range(N - 2 * mid + 1):
            memo.add(rh.get_hash(i, i + mid))
            if rh.get_hash(i + mid, i + 2 * mid) in memo:
                flg = True
                break
        if flg:
            ok = mid  # next mid will be longer
        else:
            ng = mid  # next mid will be shorter

    print(ok)  # max length of substrings appeared twice or more


if __name__ == "__main__":
    abc141_e() from typing import List class RollingHash:
    """Rolling Hash"""

    __slots__ = ["_base", "_mod", "_hash", "_power"]

    def __init__(self, source: str, base: int = 1007, mod: int = 10 ** 9 + 7):
        self._base = base
        self._mod = mod
        self._hash = self._build_hash_from_zero(source)
        self._power = self._build_base_power(len(source))

    def _build_hash_from_zero(self, source: str) -> List[int]:
        """Compute hash of interval [0, right)."""
        res = [0] * (len(source) + 1)
        for i, c in enumerate(source, 1):
            res[i] = (res[i - 1] * self._base + ord(c)) % self._mod
        return res

    def _build_base_power(self, length: int) -> List[int]:
        """Compute mod of power of base."""
        res = [1] * (length + 1)
        for i in range(1, length + 1):
            res[i] = res[i - 1] * self._base % self._mod
        return res

    def get_hash(self, left: int, right: int):
        """Return hash of interval [left, right)."""
        return (
            self._hash[right] - self._hash[left] * self._power[right - left]
        ) % self._mod RollingHash """Rolling Hash""" __slots__ = ["_base", "_mod", "_hash", "_power"] __slots__ ["_base", "_mod", "_hash", "_power"] "_base" "_mod" "_hash" "_power" def __init__(self, source: str, base: int = 1007, mod: int = 10 ** 9 + 7):
        self._base = base
        self._mod = mod
        self._hash = self._build_hash_from_zero(source)
        self._power = self._build_base_power(len(source))

     __init__ self._base = base self._base self _base base self._mod = mod self._mod self _mod mod self._hash = self._build_hash_from_zero(source) self._hash self _hash self._build_hash_from_zero(source) self._build_hash_from_zero self _build_hash_from_zero source self._power = self._build_base_power(len(source)) self._power self _power self._build_base_power(len(source)) self._build_base_power self _build_base_power len(source) len source self self source: str source base: int = 1007 base 1007 mod: int = 10 ** 9 + 7 mod 10 ** 9 + 7 10 ** 9 10 9 7 def _build_hash_from_zero(self, source: str) -> List[int]:
        """Compute hash of interval [0, right)."""
        res = [0] * (len(source) + 1)
        for i, c in enumerate(source, 1):
            res[i] = (res[i - 1] * self._base + ord(c)) % self._mod
        return res

     _build_hash_from_zero """Compute hash of interval [0, right).""" res = [0] * (len(source) + 1) res [0] * (len(source) + 1) [0] 0 len(source) + 1 len(source) len source 1 for i, c in enumerate(source, 1):
            res[i] = (res[i - 1] * self._base + ord(c)) % self._mod
         i c enumerate(source, 1) enumerate source 1 res[i] = (res[i - 1] * self._base + ord(c)) % self._mod res[i] res i (res[i - 1] * self._base + ord(c)) % self._mod res[i - 1] * self._base + ord(c) res[i - 1] * self._base res[i - 1] res i - 1 i 1 self._base self _base ord(c) ord c self._mod self _mod return res res self self source: str source def _build_base_power(self, length: int) -> List[int]:
        """Compute mod of power of base."""
        res = [1] * (length + 1)
        for i in range(1, length + 1):
            res[i] = res[i - 1] * self._base % self._mod
        return res

     _build_base_power """Compute mod of power of base.""" res = [1] * (length + 1) res [1] * (length + 1) [1] 1 length + 1 length 1 for i in range(1, length + 1):
            res[i] = res[i - 1] * self._base % self._mod
         i range(1, length + 1) range 1 length + 1 length 1 res[i] = res[i - 1] * self._base % self._mod res[i] res i res[i - 1] * self._base % self._mod res[i - 1] * self._base res[i - 1] res i - 1 i 1 self._base self _base self._mod self _mod return res res self self length: int length def get_hash(self, left: int, right: int):
        """Return hash of interval [left, right)."""
        return (
            self._hash[right] - self._hash[left] * self._power[right - left]
        ) % self._mod get_hash """Return hash of interval [left, right).""" return (
            self._hash[right] - self._hash[left] * self._power[right - left]
        ) % self._mod (
            self._hash[right] - self._hash[left] * self._power[right - left]
        ) % self._mod self._hash[right] - self._hash[left] * self._power[right - left] self._hash[right] self._hash self _hash right self._hash[left] * self._power[right - left] self._hash[left] self._hash self _hash left self._power[right - left] self._power self _power right - left right left self._mod self _mod self self left: int left right: int right def abc141_e():
    # https://atcoder.jp/contests/abc141/tasks/abc141_e
    N = int(input())
    S = input().rstrip()

    rh = RollingHash(S)
    ok, ng = 0, N // 2 + 1
    while ng - ok > 1:
        mid = (ok + ng) // 2
        flg = False
        memo = set()
        for i in range(N - 2 * mid + 1):
            memo.add(rh.get_hash(i, i + mid))
            if rh.get_hash(i + mid, i + 2 * mid) in memo:
                flg = True
                break
        if flg:
            ok = mid  # next mid will be longer
        else:
            ng = mid  # next mid will be shorter

    print(ok)  # max length of substrings appeared twice or more abc141_e N = int(input()) N int(input()) int input() input S = input().rstrip() S input().rstrip() ().rstrip () input rstrip rh = RollingHash(S) rh RollingHash(S) RollingHash S ok, ng = 0, N // 2 + 1 ok 0 ng N // 2 + 1 N // 2 N 2 1 while ng - ok > 1:
        mid = (ok + ng) // 2
        flg = False
        memo = set()
        for i in range(N - 2 * mid + 1):
            memo.add(rh.get_hash(i, i + mid))
            if rh.get_hash(i + mid, i + 2 * mid) in memo:
                flg = True
                break
        if flg:
            ok = mid  # next mid will be longer
        else:
            ng = mid  # next mid will be shorter

     ng - ok > 1 ng - ok ng ok 1 mid = (ok + ng) // 2 mid (ok + ng) // 2 ok + ng ok ng 2 flg = False flg False memo = set() memo set() set for i in range(N - 2 * mid + 1):
            memo.add(rh.get_hash(i, i + mid))
            if rh.get_hash(i + mid, i + 2 * mid) in memo:
                flg = True
                break
         i range(N - 2 * mid + 1) range N - 2 * mid + 1 N - 2 * mid N 2 * mid 2 mid 1 memo.add(rh.get_hash(i, i + mid)) memo.add memo add rh.get_hash(i, i + mid) rh.get_hash rh get_hash i i + mid i mid if rh.get_hash(i + mid, i + 2 * mid) in memo:
                flg = True
                break
         rh.get_hash(i + mid, i + 2 * mid) in memo rh.get_hash(i + mid, i + 2 * mid) rh.get_hash rh get_hash i + mid i mid i + 2 * mid i 2 * mid 2 mid memo flg = True flg True break if flg:
            ok = mid  # next mid will be longer
        else:
            ng = mid  # next mid will be shorter

     flg ok = mid ok mid ng = mid ng mid print(ok) print ok if __name__ == "__main__":
    abc141_e() __name__ == "__main__" __name__ "__main__" abc141_e() abc141_e class RollingHash:
    """Rolling Hash"""

    __slots__ = ["_base", "_mod", "_hash", "_power"]

    def __init__(self, source: str, base: int = 1007, mod: int = 10 ** 9 + 7):
        self._base = base
        self._mod = mod
        self._hash = self._build_hash_from_zero(source)
        self._power = self._build_base_power(len(source))

    def _build_hash_from_zero(self, source: str) -> List[int]:
        """Compute hash of interval [0, right)."""
        res = [0] * (len(source) + 1)
        for i, c in enumerate(source, 1):
            res[i] = (res[i - 1] * self._base + ord(c)) % self._mod
        return res

    def _build_base_power(self, length: int) -> List[int]:
        """Compute mod of power of base."""
        res = [1] * (length + 1)
        for i in range(1, length + 1):
            res[i] = res[i - 1] * self._base % self._mod
        return res

    def get_hash(self, left: int, right: int):
        """Return hash of interval [left, right)."""
        return (
            self._hash[right] - self._hash[left] * self._power[right - left]
        ) % self._mod class RollingHash:
    """Rolling Hash"""

    __slots__ = ["_base", "_mod", "_hash", "_power"]

    def __init__(self, source: str, base: int = 1007, mod: int = 10 ** 9 + 7):
        self._base = base
        self._mod = mod
        self._hash = self._build_hash_from_zero(source)
        self._power = self._build_base_power(len(source))

    def _build_hash_from_zero(self, source: str) -> List[int]:
        """Compute hash of interval [0, right)."""
        res = [0] * (len(source) + 1)
        for i, c in enumerate(source, 1):
            res[i] = (res[i - 1] * self._base + ord(c)) % self._mod
        return res

    def _build_base_power(self, length: int) -> List[int]:
        """Compute mod of power of base."""
        res = [1] * (length + 1)
        for i in range(1, length + 1):
            res[i] = res[i - 1] * self._base % self._mod
        return res

    def get_hash(self, left: int, right: int):
        """Return hash of interval [left, right)."""
        return (
            self._hash[right] - self._hash[left] * self._power[right - left]
        ) % self._mod RollingHash def abc141_e():
    # https://atcoder.jp/contests/abc141/tasks/abc141_e
    N = int(input())
    S = input().rstrip()

    rh = RollingHash(S)
    ok, ng = 0, N // 2 + 1
    while ng - ok > 1:
        mid = (ok + ng) // 2
        flg = False
        memo = set()
        for i in range(N - 2 * mid + 1):
            memo.add(rh.get_hash(i, i + mid))
            if rh.get_hash(i + mid, i + 2 * mid) in memo:
                flg = True
                break
        if flg:
            ok = mid  # next mid will be longer
        else:
            ng = mid  # next mid will be shorter

    print(ok)  # max length of substrings appeared twice or more def abc141_e():
    # https://atcoder.jp/contests/abc141/tasks/abc141_e
    N = int(input())
    S = input().rstrip()

    rh = RollingHash(S)
    ok, ng = 0, N // 2 + 1
    while ng - ok > 1:
        mid = (ok + ng) // 2
        flg = False
        memo = set()
        for i in range(N - 2 * mid + 1):
            memo.add(rh.get_hash(i, i + mid))
            if rh.get_hash(i + mid, i + 2 * mid) in memo:
                flg = True
                break
        if flg:
            ok = mid  # next mid will be longer
        else:
            ng = mid  # next mid will be shorter

    print(ok)  # max length of substrings appeared twice or more abc141_e
from typing import List


class RollingHash:
    """Rolling Hash"""

    __slots__ = ["_base", "_mod", "_hash", "_power"]

    def __init__(self, source: str, base: int = 1007, mod: int = 10 ** 9 + 7):
        self._base = base
        self._mod = mod
        self._hash = self._build_hash_from_zero(source)
        self._power = self._build_base_power(len(source))

    def _build_hash_from_zero(self, source: str) -> List[int]:
        """Compute hash of interval [0, right)."""
        res = [0] * (len(source) + 1)
        for i, c in enumerate(source, 1):
            res[i] = (res[i - 1] * self._base + ord(c)) % self._mod
        return res

    def _build_base_power(self, length: int) -> List[int]:
        """Compute mod of power of base."""
        res = [1] * (length + 1)
        for i in range(1, length + 1):
            res[i] = res[i - 1] * self._base % self._mod
        return res

    def get_hash(self, left: int, right: int):
        """Return hash of interval [left, right)."""
        return (
            self._hash[right] - self._hash[left] * self._power[right - left]
        ) % self._mod


def abc141_e():
    # https://atcoder.jp/contests/abc141/tasks/abc141_e
    N = int(input())
    S = input().rstrip()

    rh = RollingHash(S)
    ok, ng = 0, N // 2 + 1
    while ng - ok > 1:
        mid = (ok + ng) // 2
        flg = False
        memo = set()
        for i in range(N - 2 * mid + 1):
            memo.add(rh.get_hash(i, i + mid))
            if rh.get_hash(i + mid, i + 2 * mid) in memo:
                flg = True
                break
        if flg:
            ok = mid  # next mid will be longer
        else:
            ng = mid  # next mid will be shorter

    print(ok)  # max length of substrings appeared twice or more


if __name__ == "__main__":
    abc141_e()
