from typing import List


class RollingHash:
    __slots__ = ["_source", "_length", "_base", "_mod", "_hash", "_power"]

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

    def _get_hash_from_zero(self) -> List[int]:
        """Compute hash of interval [0, right)."""
        hash_from_zero = [0] * (self._length + 1)
        cur = 0
        for i, c in enumerate(self._source, 1):
            cur = (cur * self._base + ord(c)) % self._mod
            hash_from_zero[i] = cur
        return hash_from_zero

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

    def get_hash(self, left: int, right: int):
        """Compute 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:
    __slots__ = ["_source", "_length", "_base", "_mod", "_hash", "_power"]

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

    def _get_hash_from_zero(self) -> List[int]:
        """Compute hash of interval [0, right)."""
        hash_from_zero = [0] * (self._length + 1)
        cur = 0
        for i, c in enumerate(self._source, 1):
            cur = (cur * self._base + ord(c)) % self._mod
            hash_from_zero[i] = cur
        return hash_from_zero

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

    def get_hash(self, left: int, right: int):
        """Compute hash of interval [left, right)."""
        return (
            self._hash[right] - self._hash[left] * self._power[right - left]
        ) % self._mod RollingHash __slots__ = ["_source", "_length", "_base", "_mod", "_hash", "_power"] __slots__ ["_source", "_length", "_base", "_mod", "_hash", "_power"] "_source" "_length" "_base" "_mod" "_hash" "_power" def __init__(self, source: str, base: int = 1007, mod: int = 10 ** 9 + 7):
        self._source = source
        self._length = len(source)
        self._base = base
        self._mod = mod
        self._hash = self._get_hash_from_zero()
        self._power = self._get_base_pow()

     __init__ self._source = source self._source self _source source self._length = len(source) self._length self _length len(source) len source self._base = base self._base self _base base self._mod = mod self._mod self _mod mod self._hash = self._get_hash_from_zero() self._hash self _hash self._get_hash_from_zero() self._get_hash_from_zero self _get_hash_from_zero self._power = self._get_base_pow() self._power self _power self._get_base_pow() self._get_base_pow self _get_base_pow 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 _get_hash_from_zero(self) -> List[int]:
        """Compute hash of interval [0, right)."""
        hash_from_zero = [0] * (self._length + 1)
        cur = 0
        for i, c in enumerate(self._source, 1):
            cur = (cur * self._base + ord(c)) % self._mod
            hash_from_zero[i] = cur
        return hash_from_zero

     _get_hash_from_zero """Compute hash of interval [0, right).""" hash_from_zero = [0] * (self._length + 1) hash_from_zero [0] * (self._length + 1) [0] 0 self._length + 1 self._length self _length 1 cur = 0 cur 0 for i, c in enumerate(self._source, 1):
            cur = (cur * self._base + ord(c)) % self._mod
            hash_from_zero[i] = cur
         i c enumerate(self._source, 1) enumerate self._source self _source 1 cur = (cur * self._base + ord(c)) % self._mod cur (cur * self._base + ord(c)) % self._mod cur * self._base + ord(c) cur * self._base cur self._base self _base ord(c) ord c self._mod self _mod hash_from_zero[i] = cur hash_from_zero[i] hash_from_zero i cur return hash_from_zero hash_from_zero self self def _get_base_pow(self) -> List[int]:
        """Compute mod of power of base."""
        power = [0] * (self._length + 1)
        power[0] = 1
        cur = 1
        for i in range(1, self._length + 1):
            cur *= self._base % self._mod
            power[i] = cur
        return power

     _get_base_pow """Compute mod of power of base.""" power = [0] * (self._length + 1) power [0] * (self._length + 1) [0] 0 self._length + 1 self._length self _length 1 power[0] = 1 power[0] power 0 1 cur = 1 cur 1 for i in range(1, self._length + 1):
            cur *= self._base % self._mod
            power[i] = cur
         i range(1, self._length + 1) range 1 self._length + 1 self._length self _length 1 cur *= self._base % self._mod cur self._base % self._mod self._base self _base self._mod self _mod power[i] = cur power[i] power i cur return power power self self def get_hash(self, left: int, right: int):
        """Compute hash of interval [left, right)."""
        return (
            self._hash[right] - self._hash[left] * self._power[right - left]
        ) % self._mod get_hash """Compute 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 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 class RollingHash:
    __slots__ = ["_source", "_length", "_base", "_mod", "_hash", "_power"]

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

    def _get_hash_from_zero(self) -> List[int]:
        """Compute hash of interval [0, right)."""
        hash_from_zero = [0] * (self._length + 1)
        cur = 0
        for i, c in enumerate(self._source, 1):
            cur = (cur * self._base + ord(c)) % self._mod
            hash_from_zero[i] = cur
        return hash_from_zero

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

    def get_hash(self, left: int, right: int):
        """Compute hash of interval [left, right)."""
        return (
            self._hash[right] - self._hash[left] * self._power[right - left]
        ) % self._mod class RollingHash:
    __slots__ = ["_source", "_length", "_base", "_mod", "_hash", "_power"]

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

    def _get_hash_from_zero(self) -> List[int]:
        """Compute hash of interval [0, right)."""
        hash_from_zero = [0] * (self._length + 1)
        cur = 0
        for i, c in enumerate(self._source, 1):
            cur = (cur * self._base + ord(c)) % self._mod
            hash_from_zero[i] = cur
        return hash_from_zero

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

    def get_hash(self, left: int, right: int):
        """Compute hash of interval [left, right)."""
        return (
            self._hash[right] - self._hash[left] * self._power[right - left]
        ) % self._mod RollingHash
from typing import List


class RollingHash:
    __slots__ = ["_source", "_length", "_base", "_mod", "_hash", "_power"]

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

    def _get_hash_from_zero(self) -> List[int]:
        """Compute hash of interval [0, right)."""
        hash_from_zero = [0] * (self._length + 1)
        cur = 0
        for i, c in enumerate(self._source, 1):
            cur = (cur * self._base + ord(c)) % self._mod
            hash_from_zero[i] = cur
        return hash_from_zero

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

    def get_hash(self, left: int, right: int):
        """Compute 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()
