AtCoder Beginner Contest 141 - Who Says a Pun?

Given is a string S of length N.
Find the maximum length of a non-empty string that occurs twice or more in S as contiguous substrings without overlapping.
More formally, find the maximum positive integer len such that there exist integers l_1 and l_2 ( 1 \leq l_1, l_2 \leq N - len + 1 ) that satisfy the following:
 - l_1 + len \leq l_2
 - S[l_1+i] = S[l_2+i] (i = 0, 1, ..., len - 1)
If there is no such integer len, print 0.

-----Constraints-----
 - 2 \leq N \leq 5 \times 10^3
 - |S| = N
 - S consists of lowercase English letters.

-----Input-----
Input is given from Standard Input in the following format:
N
S

-----Output-----
Print the maximum length of a non-empty string that occurs twice or more in S as contiguous substrings without overlapping. If there is no such non-empty string, print 0 instead.

-----Sample Input-----
5
ababa

-----Sample Output-----
2

The strings satisfying the conditions are: a, b, ab, and ba. The maximum length among them is 2, which is the answer.
Note that aba occurs twice in S as contiguous substrings, but there is no pair of integers l_1 and l_2 mentioned in the statement such that l_1 + len \leq l_2.

Source: atcoder | Difficulty: MEDIUM_HARD


Solutions:
n = int(input())
s = input()
l = 0
r = 1
ans = 0
while r < n:
	if s[l:r] in s[r:]:
		ans = max(ans, r - l)
		r += 1
	else:
		l += 1
	if l == r:
		l += 1
		r += 2
print(ans)


N = int(input())
S = str(input())
ans = 0
j = 0
for i in range(N):
	while j < N and S[i:j] in S[j:]:
		ans = max(ans, j - i)
		j += 1
print(ans)


N = int(input())
S = input()

def f(m):
	se = set()
	arr = [None] * N
	for i in range(0, N - m + 1):
		if i >= m:
			se.add(arr[i - m])
		arr[i] = hash(S[i:i + m])
		if arr[i] in se:
			return True
	return False
l = 0
r = N // 2 + 1
while r - l > 1:
	mid = (r + l) // 2
	if f(mid):
		l = mid
	else:
		r = mid
print(l)


def solve():
	N = int(input())
	S = input()

	def rolling_hash(s, mod, base=37):
		l = len(s)
		h = [0] * (l + 1)
		v = 0
		for i in range(l):
			h[i + 1] = v = (v * base + ord(s[i])) % mod
		pw = [1] * (l + 1)
		v = 1
		for i in range(l):
			pw[i + 1] = v = v * base % mod
		return (h, pw)

	def chk(S, mod, D=[0] * N):
		(h, pw) = rolling_hash(S, mod)
		left = 0
		right = N // 2 + 1
		while left + 1 < right:
			l = mid = left + right >> 1
			p = pw[l]
			for i in range(min(l, N - 2 * l + 1)):
				D[i] = (h[l + i] - h[i] * p) % mod
			s = set()
			ok = 0
			for i in range(l, N - l + 1):
				s.add(D[i - l])
				D[i] = v = (h[l + i] - h[i] * p) % mod
				if v in s:
					ok = 1
					break
			if ok:
				left = mid
			else:
				right = mid
		return left
	print(chk(S, 10 ** 9 + 9))
solve()


N = int(input())
S = input()
(l, u) = (0, N)
while l + 1 < u:
	m = (l + u) // 2
	s = set()
	for i in range(N - m * 2 + 1):
		s.add(S[i:i + m])
		if S[i + m:i + m * 2] in s:
			l = m
			break
	if l != m:
		u = m
print(l)


N = int(input())
S = input()
dp = [[0] * (N + 1) for _ in range(N + 1)]
ans = 0
for i in range(N - 1, -1, -1):
	for j in range(N - 1, -1, -1):
		if i >= j:
			break
		if S[i] == S[j]:
			dp[i][j] = min(1 + dp[i + 1][j + 1], j - i)
			if dp[i][j] > ans:
				ans = dp[i][j]
print(ans)


int(input())
s = input()
l = 0
r = 1
ans = 0
while l < len(s) - 1:
	ss = s[l:r]
	sss = s[r:]
	if ss in sss:
		ans = max(ans, len(ss))
		r += 1
	else:
		l += 1
print(ans)


N = int(input())
S = input()
from collections import deque

def f(m):
	se = set()
	q = deque()
	for i in range(0, N - m + 1):
		h = hash(S[i:i + m])
		q.append(h)
		if h in se:
			return True
		if len(q) >= m:
			se.add(q.popleft())
	return False
l = 0
r = N // 2 + 1
while r - l > 1:
	mid = (r + l) // 2
	if f(mid):
		l = mid
	else:
		r = mid
print(l)


n = int(input())
s = input()
max_len = 0
j = 0
for i in range(n):
	while j < n and s[i:j] in s[j:]:
		j += 1
	max_len = max(max_len, j - i - 1)
print(max_len)


n = int(input())
s = list(input())
f = 0
b = -1
for d in range(1, n):
	c = 0
	b = -1
	for i in range(n - d):
		if s[i] == s[i + d] and c < d:
			if b == -1:
				b = i
			c += 1
			f = max(f, c)
			if c >= d:
				break
		else:
			c = 0
			b = -1
print(f)


n = int(input())
s = input()
j = 1
for i in range(n):
	seq = s[i:i + j]
	while s[i + j:].find(seq) != -1:
		j += 1
		seq = s[i:i + j]
print(j - 1)


N = int(input())
S = input()
a = 0
i = 0
j = 1
while j < N:
	if S[i:j] in S[j:]:
		a = max(a, len(S[i:j]))
		j += 1
	else:
		i += 1
	if i == j:
		i += 1
		j += 2
print(a)


n = int(input())
s = input()
a = 0
i = 0
j = 1
while j < n:
	if s[i:j] in s[j:]:
		a = max(a, len(s[i:j]))
		j += 1
	else:
		i += 1
	if i == j:
		i += 1
		j += 2
print(a)


N = int(input())
S = input()
dp = [[0] * (N + 1) for i in range(N + 1)]
ans = 0
for i in range(N - 1, -1, -1):
	for j in range(i, -1, -1):
		if S[i] == S[j]:
			dp[i][j] = dp[i + 1][j + 1] + 1
			tmp = min(dp[i][j], i - j)
			ans = max(ans, tmp)
print(ans)


N = int(input())
S = input()
ans = 0
right = 0
for left in range(N):
	while S[left:right + 1] in S[right + 1:]:
		ans = max(ans, right + 1 - left)
		right += 1
print(ans)


n = int(input())
s = input()
j = 1
result = []
for i in range(n):
	while j < n - 1 and s[i:j] in s[j:]:
		j += 1
	result.append(j - i - 1)
print(max(result))


import sys
input = sys.stdin.readline

def main():
	n = int(input())
	s = input()[::-1]
	ans = 0
	l = 0
	r = 1
	for r in range(1, n):
		if s[l:r] in s[r:]:
			ans = r - l
		else:
			l += 1
	print(ans)
main()


from collections import defaultdict

class RollingHash(object):

	def __init__(self, S: str, MOD: int=10 ** 9 + 7, BASE: int=10 ** 5 + 7):
		self.S = S
		self.N = N = len(S)
		self.MOD = MOD
		self.BASE = BASE
		self.S_arr = [ord(x) for x in S]
		self.POWER = [1] * (N + 1)
		self.HASH = [0] * (N + 1)
		(p, h) = (1, 0)
		for i in range(N):
			self.POWER[i + 1] = p = p * BASE % MOD
			self.HASH[i + 1] = h = (h * BASE + self.S_arr[i]) % MOD

	def hash(self, l: int, r: int):
		_hash = self.HASH[r] - self.HASH[l] * self.POWER[r - l] % self.MOD
		if _hash < 0:
			_hash += self.MOD
		return _hash

def binary_search(left: int, right: int, check_func, search_max: bool=False):
	while abs(right - left) > 1:
		mid = (left + right) // 2
		if check_func(mid) ^ search_max:
			right = mid
		else:
			left = mid
	return left if search_max else right

def main():
	N = int(input())
	S = input()
	rs = RollingHash(S)

	def isOK(L):
		if L == 0:
			return True
		hash_to_left = defaultdict(list)
		for i in range(N - L + 1):
			_hash = rs.hash(i, i + L)
			for j in hash_to_left[_hash]:
				if j + L <= i and S[i:i + L] == S[j:j + L]:
					return True
			hash_to_left[_hash].append(i)
		return False
	ans = binary_search(0, N // 2 + 1, isOK, search_max=True)
	print(ans)

def __starting_point():
	main()
__starting_point()


n = int(input())
s = input()
l = 0
r = n // 2
while r - l >= 1:
	m = (r + l + 1) // 2
	d = {}
	flg = False
	for i in range(n - m + 1):
		t = s[i:i + m]
		if t in d:
			if d[t] + m - 1 < i:
				flg = True
				break
		else:
			d[t] = i
	if flg:
		l = m
	else:
		r = m - 1
print(l)


def resolve():
	N = int(input())
	S = input().rstrip()
	(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(hash(S[i:i + mid]))
			if hash(S[i + mid:i + 2 * mid]) in memo:
				flg = True
				break
		if flg:
			ok = mid
		else:
			ng = mid
	print(ok)
resolve()


(n, s) = open(0)
a = i = j = 0
while s[j:]:
	f = s[i:j] in s[j:]
	a = max(a, j * f - i)
	j += f
	i += f ^ 1
print(a)


n = int(input())
s = list(input())
res = 0
dp = [[0] * (n + 1) for _ in range(n + 1)]
for i in reversed(range(n)):
	for j in reversed(range(i + 1, n)):
		if s[i] == s[j]:
			dp[i][j] = dp[i + 1][j + 1] + 1
		cres = min(j - i, dp[i][j])
		res = max(res, cres)
print(res)


(n, s) = (int(input()), input())
dp = [[0] * (n + 1) for i in range(n + 1)]
for i in range(n):
	for j in range(i + 1, n):
		if s[i] == s[j]:
			dp[i + 1][j + 1] = min(dp[i][j] + 1, j - i)
from itertools import chain
print(max((i for i in chain.from_iterable(dp))))


def p_e():
	N = int(input())
	S = input()
	(l, r, ans) = (0, 0, 0)
	while r < N:
		if S[l:r] in S[r:N]:
			ans = max(ans, r - l)
			r += 1
		else:
			l += 1
	print(ans)
p_e()


(n, s) = open(0)
j = r = 0
for i in range(int(n)):
	while j < int(n) and s[i:j] in s[j:]:
		j += 1
	r = max(r, j - i - 1)
print(r)


n = int(input())
s = input()
max_l = 0
for i in range(n):
	for l in range(max_l + 1, (n - i) // 2 + 1):
		if s[i:i + l] in s[i + l:]:
			if l > max_l:
				max_l = l
		else:
			break
print(max_l)


from collections import defaultdict as dd
N = int(input())
s = str(input())
maxlen = N // 2

def solve(tgt):
	dic = dd(int)
	st = s[tgt:2 * tgt]
	dic[st] += 1
	ls = [st]
	for char in s[2 * tgt:]:
		st = st[1:] + char
		dic[st] += 1
		ls.append(st)
	st = s[:tgt]
	if dic[st] > 0:
		return True
	dic[ls[0]] -= 1
	for (i, char) in enumerate(s[tgt:N - tgt]):
		st = st[1:] + char
		if dic[st] > 0:
			return True
		dic[ls[i + 1]] -= 1
	return False
ng = maxlen + 1
ok = 0
while ng - ok > 1:
	tgt = (ok + ng) // 2
	if solve(tgt):
		ok = tgt
	else:
		ng = tgt
print(ok)


def solve():
	N = int(input())
	Ss = input().rstrip()

	def isOK(L):
		setCand = set()
		RHs = []
		for i in range(N - L + 1):
			RH = hash(Ss[i:i + L])
			RHs.append(RH)
			if i - L >= 0:
				setCand.add(RHs[i - L])
			if RH in setCand:
				return True
		return False
	(ng, ok) = (N // 2 + 1, 0)
	while abs(ok - ng) > 1:
		mid = (ng + ok) // 2
		if isOK(mid):
			ok = mid
		else:
			ng = mid
	print(ok)
solve()


from collections import deque
N = int(input())
S = input()

def exists(length):
	que = deque()
	V = set()
	for left in range(N - length + 1):
		if left > length - 1:
			V.add(que.popleft())
		T = S[left:left + length]
		if T in V:
			return True
		que.append(T)
	return False
ok = 0
ng = N
while ng - ok > 1:
	mid = (ok + ng) // 2
	if exists(mid):
		ok = mid
	else:
		ng = mid
print(ok)


n = int(input())
s = input()
(ok, ng) = (0, n // 2 + 1)
while ng - ok > 1:
	x = (ok + ng) // 2
	possible = False
	d = set()
	for i in range(n - 2 * x + 1):
		d.add(s[i:i + x])
		if s[i + x:i + 2 * x] in d:
			possible = True
			break
	if possible:
		ok = x
	else:
		ng = x
print(ok)


N = int(input())
S = input()
length = 0
for i in range(N):
	l1 = i
	l2 = i + length
	_word = S[l1:l2]
	_S = S[l2:]
	while _word in _S:
		l2 += 1
		_word = S[l1:l2]
		_S = S[l2:]
	length = max(len(_word) - 1, length)
print(length)


n = int(input())
s = input()
ans = 0
right = 1
for left in range(n):
	while s[left:right] in s[right:]:
		ans = max(ans, right - left)
		right += 1
print(ans)


N = int(input())
S = input()
ans = 0
for i in range(N):
	j_start = ans + 1
	for j in range(j_start, N - i):
		base = S[i:i + j]
		if base in S[i + j:]:
			ans = max(ans, j)
		else:
			break
print(ans)


N = int(input())
S = input()
l = 0
k = 1
for i in range(N - 1):
	while True:
		if S[i:i + k] in S[i + k:]:
			k += 1
		else:
			break
	l = max(l, k - 1)
print(l)


def main():
	n = int(input())
	s = input()
	(i, j) = (0, 1)
	ans = 0
	while j < n:
		if s[i:j] in s[j:]:
			if j - i > ans:
				ans = j - i
			j += 1
		else:
			i += 1
			j += 1
	print(ans)
main()


N = int(input())
S = input()
k = 1
for i in range(N - 1):
	while i + k <= N and S[i:i + k] in S[i + k:]:
		k += 1
print(k - 1)


import random

class RollingHash(object):

	def __init__(self, S: str, MOD: int=10 ** 9 + 7, BASE: int=10 ** 5 + 7):
		self.S = S
		self.N = N = len(S)
		self.MOD = MOD
		self.BASE = BASE
		self.S_arr = [ord(x) for x in S]
		self.POWER = [1] * (N + 1)
		self.HASH = [0] * (N + 1)
		(p, h) = (1, 0)
		for i in range(N):
			self.POWER[i + 1] = p = p * BASE % MOD
			self.HASH[i + 1] = h = (h * BASE + self.S_arr[i]) % MOD

	def hash(self, l: int, r: int):
		_hash = (self.HASH[r] - self.HASH[l] * self.POWER[r - l]) % self.MOD
		return _hash

def binary_search(left: int, right: int, check_func, search_max: bool=False):
	while abs(right - left) > 1:
		mid = (left + right) // 2
		if check_func(mid) ^ search_max:
			right = mid
		else:
			left = mid
	return left if search_max else right

def main():
	N = int(input())
	S = input()
	MOD = 998244353
	BASE = 37
	rs = RollingHash(S, MOD=MOD, BASE=BASE)
	D = [0] * N

	def isOK(L):
		if L == 0:
			return True
		for i in range(min(L, N - 2 * L + 1)):
			D[i] = rs.hash(i, i + L)
		hashes = set()
		for i in range(L, N - L + 1):
			hashes.add(D[i - L])
			D[i] = v = rs.hash(i, i + L)
			if v in hashes:
				return True
		return False
	ans = binary_search(0, N // 2 + 1, isOK, search_max=True)
	print(ans)

def __starting_point():
	main()
__starting_point()


n = int(input())
s = input()
ans = 0
lenS = 1
for i in range(n):
	tempS = s[i:i + lenS]
	while tempS in s[i + lenS:]:
		lenS += 1
		tempS = s[i:i + lenS]
		ans += 1
	if i + 2 * lenS >= n:
		break
print(ans)


N = int(input())
S = input()

def check(L):
	a = set()
	for i in range(N - L * 2 + 1):
		a.add(S[i:i + L])
		if S[i + L:i + L + L] in a:
			return True
	return False
left = 0
right = N // 2 + 1
while right - left > 1:
	mid = left + (right - left) // 2
	if check(mid):
		left = mid
	else:
		right = mid
print(left)


def ok(l):
	D = {}
	for i in range(n - l + 1):
		try:
			if D[S[i:i + l]] + l <= i:
				return True
		except:
			D[S[i:i + l]] = i
	return False
n = int(input())
S = input()
(l, r) = (0, n + 1)
while r - l > 1:
	c = (l + r) // 2
	if ok(c):
		l = c
	else:
		r = c
print(l)


n = int(input())
s = input()
l = 0
r = n
while r - l > 1:
	mid = (r + l) // 2
	dic = {}
	flag = False
	for i in range(n - mid + 1):
		tmp = s[i:i + mid]
		if tmp not in dic:
			dic[tmp] = i + mid
		elif dic[tmp] <= i:
			flag = True
			break
	if flag:
		l = mid
	else:
		r = mid
print(l)


n = int(input())
s = input()
dp = [[0] * (n + 1) for i in range(n + 1)]
ans = 0
for i in range(n - 1, -1, -1):
	for j in range(n - 1, i, -1):
		if s[i] == s[j]:
			dp[i][j] = dp[i + 1][j + 1] + 1
		else:
			dp[i][j] = 0
		ans = max(ans, min(dp[i][j], j - i))
print(ans)


N = int(input())
S = input()
r = 1
ans = 0
for l in range(N):
	while True:
		if S.rfind(S[l:r + 1]) >= r + 1:
			r += 1
			ans = max(ans, r - l)
		else:
			break
print(ans)


n = int(input())
s = input()
i = 0
j = 0
r = 0
while i < n:
	if s[i:j] in s[j:]:
		r = max(r, j - i)
		j += 1
	else:
		i += 1
print(r)


I = input
n = int(I())
s = I()
j = r = 0
for i in range(n):
	while j < n and s[i:j] in s[j:]:
		j += 1
	r = max(r, j - i - 1)
print(r)


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._build_hash_from_zero()
		self._power = self._build_base_power()

	def _build_hash_from_zero(self) -> List[int]:
		res = [0] * (self._length + 1)
		prev = 0
		for (i, c) in enumerate(self._source, 1):
			res[i] = (prev * self._base + ord(c)) % self._mod
			prev = res[i]
		return res

	def _build_base_power(self) -> List[int]:
		res = [1] * (self._length + 1)
		prev = 1
		for i in range(1, self._length + 1):
			res[i] = prev * self._base % self._mod
			prev = res[i]
		return res

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

def 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
		else:
			ng = mid
	print(ok)

def __starting_point():
	abc141_e()
__starting_point()


n = int(input())
s = input()
yes = 0
no = n // 2 + 1
while abs(yes - no) > 1:
	center = (yes + no) // 2
	d = set()
	for i in range(n - 2 * center + 1):
		d.add(s[i:i + center])
		if s[i + center:i + 2 * center] in d:
			yes = center
			break
	if yes != center:
		no = center
print(yes)


class RollingHash:

	def __init__(self, s, base, mod):
		self.mod = mod
		self.pw = pw = [1] * (len(s) + 1)
		l = len(s)
		self.h = h = [0] * (l + 1)
		v = 0
		for i in range(l):
			h[i + 1] = v = (v * base + ord(s[i])) % mod
		v = 1
		for i in range(l):
			pw[i + 1] = v = v * base % mod

	def get(self, l, r):
		return (self.h[r] - self.h[l] * self.pw[r - l]) % self.mod

	def check(self, d):
		ma = {}
		for i in range(N - d + 1):
			p = self.get(i, i + d)
			if p in ma:
				if i - ma[p] >= d:
					return True
			else:
				ma[p] = i
		return False
N = int(input())
S = str(input())
base1 = 1007
mod1 = 10 ** 9 + 7
RH = RollingHash(S, base1, mod1)
left = 0
right = N // 2 + 1
while right - left > 1:
	mid = (left + right) // 2
	if RH.check(mid):
		left = mid
	else:
		right = mid
print(left)


N = int(input())
S = input()
i = j = 0
ans = 0
while j < N - 1:
	if S[i:j] in S[j:]:
		ans = max(ans, j - i)
		j += 1
	else:
		i += 1
print(ans)


n = int(input())
s = input()
ans = 0
for i in range(n):
	if n < i + ans:
		break
	if s[i + 1:].find(s[i - ans:i + 1]) != -1:
		ans += 1
print(ans)


n = int(input())
s = str(input())
a = ''
ans = 0
for i in range(n):
	a += s[i]
	while len(a) > 0:
		if a in s[i + 1:]:
			ans = max(ans, len(a))
			break
		else:
			a = a[1:]
print(ans)


N = int(input())
S = input()
ans = 0
(left, right) = (0, 1)
while right < N:
	s = S[left:right]
	if s in S[right:]:
		ans = max(ans, len(s))
		right += 1
	else:
		left += 1
print(ans)


N = int(input())
S = input()
long = 0
for i in range(N - 1):
	for j in range(i + long + 1, N):
		if not S[i:j] in S[j:]:
			break
	long = max(long, j - i - 1)
print(long)


n = int(input())
s = input()
dp = [[0] * (n + 1) for i in range(n + 1)]
for i in range(n - 1, -1, -1):
	for j in range(n - 1, i, -1):
		if s[j] == s[i] and dp[i + 1][j + 1] + 1 <= j - i:
			dp[i][j] = dp[i + 1][j + 1] + 1
ans = 0
for i in range(n):
	for j in range(n):
		ans = max(ans, dp[i][j])
print(ans)


n = int(input())
s = input()
x = 0
for i in range(n):
	s_ = s[:i + 1]
	if s_[i - x:] in s_[:i - x]:
		x += 1
print(x)


import numpy as np

def main():
	n = int(input())
	s = list(input())
	for i in range(n):
		s[i] = ord(s[i]) - ord('a')
	s = np.array(s)
	dp = np.zeros((n + 1, n + 1), dtype=np.int64)
	tmp = np.arange(0, n + 1)
	t = np.zeros((n + 1, n + 1))
	for i in range(n + 1):
		t[i] += tmp
		tmp -= 1
	for i in range(n):
		c = s[i]
		equal = c == s
		dp[i + 1][1:] += equal
		dp[i + 1][1:] += equal * dp[i][:-1]
	dp = np.minimum(dp, t)
	ans = 0
	for i in range(1, n):
		tmp = dp[i][i + 1:]
		tmp = tmp[ans < tmp]
		if 0 < len(tmp):
			ans = max(ans, max(tmp))
	print(int(ans))

def __starting_point():
	main()
__starting_point()


N = int(input())
S = input()
T = [[0 for _ in range(N)] for _ in range(N)]
for i in range(N):
	for j in range(i + 1, N):
		if S[i] == S[j]:
			T[i][j] += T[i - 1][j - 1] + 1
answer = 0
for i in range(N):
	for j in range(N):
		if T[i][j] and j - i >= T[i][j]:
			answer = max(answer, T[i][j])
print(answer)


N = int(input())
S = input()
res = 0
for k in range(1, N):
	cnt = 0
	for i in range(N - k):
		if i + k < N and S[i + k] == S[i]:
			cnt += 1
		else:
			cnt = 0
		cnt = min(k, cnt)
		res = max(cnt, res)
print(res)


n = int(input())
S = input()
N = [0] * n
j = 0
for i in range(n):
	while S[i:j] in S[j:n]:
		N[i] = j - i
		j += 1
print(max(N))


def main():
	N = int(input())
	S = input()
	ans = 0
	index = 0
	for i in range(N):
		s1 = S[index:i + 1]
		s2 = S[i + 1:]
		if s1 in s2:
			ans = len(s1)
		else:
			index += 1
	print(ans)
main()


import sys
from collections import defaultdict, deque
from heapq import heappush, heappop
import math
import bisect
input = sys.stdin.readline
n = int(input())
s = input()[:-1]
lb = 0
ub = n // 2 + 1

def check(len):
	for l1 in range(n - len):
		for l2 in range(l1 + len, n - len + 1):
			if s[l1:l1 + len] == s[l2:l2 + len]:
				return True
	return False

def check3(m):
	dic = defaultdict(str)
	for i in range(n - m + 1):
		s_ = s[i:i + m]
		if s_ in dic.keys():
			if dic[s_] + m <= i:
				return True
		else:
			dic[s_] = i
	return False
mod = 10 ** 9 + 7
base = 1234
power = [1] * (n + 1)
for i in range(1, n + 1):
	power[i] = power[i - 1] * base % mod

def check2(m):
	res = 0
	for i in range(m):
		res += s[i] * power[m - i - 1]
		res %= mod
	dic = {res: 0}
	for i in range(n - m):
		res = ((res - s[i] * power[m - 1]) * base + s[i + m]) % mod
		if res in dic.keys():
			index = dic[res]
			if index + m <= i + 1:
				return True
		else:
			dic[res] = i + 1
	return False
while ub > lb + 1:
	x = (lb + ub) // 2
	if check3(x):
		lb = x
	else:
		ub = x
print(lb)


import numpy as np
n = int(input())
s = np.array(list(input()))
l = s.size
dp = np.zeros(l, dtype=np.int16)
ans = 0
for (i, e) in enumerate(s, 1):
	dp_prev = dp[:]
	mx = np.arange(1, l + 1) - i
	idx = np.hstack([np.full(i, False), s[i:] == e]).astype(np.bool)
	idx_prev = np.hstack([np.full(i - 1, False), s[i:] == e, False]).astype(np.bool)
	dp = np.zeros(l, dtype=np.int16)
	dp[idx] = np.minimum(dp_prev[idx_prev] + 1, mx[idx])
	ans = max(ans, dp.max())
print(ans)


class RollingHash(object):

	def __init__(self, S, base, mod):
		self.mod = mod
		l = len(S)
		self.hash_lst = [0] * (l + 1)
		self.pow_lst = [1] * (l + 1)
		for i in range(l):
			self.hash_lst[i + 1] = (self.hash_lst[i] * base + ord(S[i])) % mod
			self.pow_lst[i + 1] = self.pow_lst[i] * base % mod

	def get_hash(self, left, right):
		return (self.hash_lst[right] - self.hash_lst[left] * self.pow_lst[right - left] % self.mod) % self.mod
N = int(input())
S = input()
base = 1007
mod = pow(10, 9) + 7
rh = RollingHash(S, base, mod)
left = 0
right = N // 2
while left <= right:
	mid = (left + right) // 2
	found_hash = {}
	found = False
	for i in range(N - mid + 1):
		h = rh.get_hash(i, i + mid)
		if h not in found_hash:
			found_hash[h] = i
		elif found_hash[h] <= i - mid:
			found = True
			break
	if found:
		left = mid + 1
	else:
		right = mid - 1
print(right)


(n, s) = open(0)
n = int(n)
a = 0
for i in range(n):
	t = 0
	for (v, w) in zip(s, s[i:n]):
		t = -~t * (v == w)
		a = max(a, min(t, i))
print(a)


n = int(input())
s = input()
mx = 0
for i in range(1, n):
	c = 0
	for j in range(n - i):
		if s[j] == s[j + i]:
			c += 1
			mx = max(mx, c)
			if c == i:
				break
		else:
			c = 0
print(mx)


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]:
		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]:
		power = [1] * (self.length + 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):
		return (self.hash[right] - self.hash[left] * self.power[right - left]) % self.mod

def 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
		else:
			ng = mid
	print(ok)

def __starting_point():
	abc141_e()
__starting_point()


N = int(input())
S = input()
max = 0
index = 0
for i in range(1, len(S) - 1):
	s1 = S[index:i]
	s2 = S[i:]
	if s1 in s2:
		max = len(s1)
	else:
		index += 1
print(max)


n = int(input())
s = list(input())
res = 0
for k in range(1, n):
	d = [0] * n
	for i in range(n - k):
		if i + k <= n - 1 and s[i] == s[i + k]:
			d[i] = min(k, d[i - 1] + 1)
			res = max(res, d[i])
print(res)


N = int(input())
S = input()
l = 0
r = N
while l + 1 < r:
	x = (l + r) // 2
	first_loc = {}
	possible = False
	for i in range(N - x + 1):
		sub = S[i:i + x]
		if sub in first_loc:
			if first_loc[sub] <= i - x:
				possible = True
				break
		else:
			first_loc[sub] = i
	if possible:
		l = x
	else:
		r = x
print(l)


n = int(input())
S = input()
ans = 0
for d in range(n):
	cnt = 0
	for i in range(n - d):
		if S[i] == S[d + i]:
			cnt += 1
		else:
			cnt = 0
		ans = max(ans, min(cnt, d))
print(ans)


n = int(input())
s = input()

def search(x):
	d = set()
	for i in range(n - 2 * x + 1):
		d.add(s[i:i + x])
		if s[i + x:i + 2 * x] in d:
			return True
	return False
l = 0
r = n // 2 + 1
while r > l + 1:
	mid = (r + l) // 2
	if search(mid):
		l = mid
	else:
		r = mid
print(l)


N = int(input())
S = input()
res = 0
dp = [[0] * (N + 1) for _ in range(N + 1)]
for i in range(N - 1, -1, -1):
	for j in range(N - 1, i, -1):
		if S[i] == S[j]:
			dp[i][j] = max(dp[i][j], dp[i + 1][j + 1] + 1)
		res = max(res, min(dp[i][j], j - i))
print(res)


n = int(input())
s = input()
_max = 0
for i in range(n):
	for j in range(i + 1, n):
		if _max >= j - i:
			continue
		part = s[i:j]
		if part in s[j:]:
			_max = j - i
		else:
			break
print(_max)


N = int(input())
S = input()
dp = [[0] * (N + 1) for _ in range(N + 1)]
for l in range(N)[::-1]:
	for r in range(l + 1, N)[::-1]:
		dp[l][r] = dp[l + 1][r + 1] + 1 if S[l] == S[r] else 0
ans = 0
for l in range(N)[::-1]:
	for r in range(l + 1, N)[::-1]:
		ans = max(ans, min(r - l, dp[l][r]))
print(ans)


N = int(input())
S = input()
i = 0
j = 1
res = 0
while j < N:
	sub = S[i:j]
	main = S[j:]
	if sub in main:
		j += 1
		res = max(res, len(sub))
	else:
		i += 1
	if i == j:
		i += 1
		j += 2
print(res)


n = int(input())
s = input()
ans = 0
for d in range(1, n):
	count = 0
	for i in range(n - d):
		if s[i] == s[i + d]:
			count += 1
		else:
			count = 0
		ans = max(min(count, d), ans)
print(ans)


from collections import defaultdict, deque, Counter, OrderedDict
from bisect import bisect_left, bisect_right
from functools import reduce, lru_cache
from heapq import heappush, heappop, heapify
import itertools
import math, fractions
import sys, copy

def L():
	return sys.stdin.readline().split()

def I():
	return int(sys.stdin.readline().rstrip())

def SL():
	return list(sys.stdin.readline().rstrip())

def LI():
	return [int(x) for x in sys.stdin.readline().split()]

def LI1():
	return [int(x) - 1 for x in sys.stdin.readline().split()]

def LS():
	return [list(x) for x in sys.stdin.readline().split()]

def R(n):
	return [sys.stdin.readline().strip() for _ in range(n)]

def LR(n):
	return [L() for _ in range(n)]

def IR(n):
	return [I() for _ in range(n)]

def LIR(n):
	return [LI() for _ in range(n)]

def LIR1(n):
	return [LI1() for _ in range(n)]

def SR(n):
	return [SL() for _ in range(n)]

def LSR(n):
	return [LS() for _ in range(n)]

def perm(n, r):
	return math.factorial(n) // math.factorial(r)

def comb(n, r):
	return math.factorial(n) // (math.factorial(r) * math.factorial(n - r))

def make_list(n, *args, default=0):
	return [make_list(*args, default=default) for _ in range(n)] if len(args) > 0 else [default for _ in range(n)]
dire = [[1, 0], [0, 1], [-1, 0], [0, -1]]
dire8 = [[1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1], [0, -1], [1, -1]]
alphabets = 'abcdefghijklmnopqrstuvwxyz'
ALPHABETS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
MOD = 1000000007
INF = float('inf')
sys.setrecursionlimit(1000000)

class DoubleRollingHash:

	def __init__(self, seq, f=ord):
		self.n = len(seq)
		(self.base1, self.base2) = (1007, 2009)
		(self.mod1, self.mod2) = (1000000007, 1000000009)
		self.f = f
		(self.hash1, self.hash2) = ([0] * (self.n + 1), [0] * (self.n + 1))
		(self.power1, self.power2) = ([1] * (self.n + 1), [1] * (self.n + 1))
		for (i, e) in enumerate(seq):
			self.hash1[i + 1] = (self.hash1[i] * self.base1 + self.f(e)) % self.mod1
			self.hash2[i + 1] = (self.hash2[i] * self.base2 + self.f(e)) % self.mod2
			self.power1[i + 1] = self.power1[i] * self.base1 % self.mod1
			self.power2[i + 1] = self.power2[i] * self.base2 % self.mod2

	def get(self, l, r):
		v1 = (self.hash1[r] - self.hash1[l] * self.power1[r - l]) % self.mod1
		v2 = (self.hash2[r] - self.hash2[l] * self.power2[r - l]) % self.mod2
		return (v1, v2)

	def getLCP(self, a, b):
		l = self.n - max(a, b) + 1
		(left, right) = (0, l)
		while right - left > 1:
			mid = (left + right) // 2
			if self.get(a, a + mid) == self.get(b, b + mid):
				left = mid
			else:
				right = mid
		return left

class RollingHash:

	def __init__(self, seq, f=ord):
		self.n = len(seq)
		(self.base, self.mod) = (1007, pow(2, 61) - 1)
		self.f = f
		(self.hash, self.power) = ([0] * (self.n + 1), [1] * (self.n + 1))
		for (i, e) in enumerate(seq):
			self.hash[i + 1] = (self.hash[i] * self.base + self.f(e)) % self.mod
			self.power[i + 1] = self.power[i] * self.base % self.mod

	def get(self, l, r):
		return (self.hash[r] - self.hash[l] * self.power[r - l]) % self.mod

	def getLCP(self, a, b):
		l = self.n - max(a, b) + 1
		(left, right) = (0, l)
		while right - left > 1:
			mid = (left + right) // 2
			if self.get(a, a + mid) == self.get(b, b + mid):
				left = mid
			else:
				right = mid
		return left

def main():
	N = I()
	S = SL()
	rh = RollingHash(S)
	ans = 0

	def check(m):
		d = defaultdict(lambda : -1)
		for i in range(N - m + 1):
			v = rh.get(i, i + m)
			if d[v] != -1:
				if i >= d[v] + m:
					return True
			else:
				d[v] = i
		return False
	(left, right) = (0, N // 2 + 1)
	while right - left > 1:
		mid = (left + right) // 2
		if check(mid):
			left = mid
		else:
			right = mid
	print(left)

def __starting_point():
	main()
__starting_point()


n = int(input())
s = input()
ans = 0
tmp = 0
for i in range(n - 1):
	for j in range(i + 2, n + 1):
		if j - i > ans:
			if s[i:j] in s[j:]:
				tmp = j - i
			else:
				ans = max(tmp, ans)
				break
ans = max(tmp, ans)
print(ans)


n = int(input())
s = input()
l1 = l2 = length = 0
while l2 + length < n:
	if s[l1:l2] in s[l2:]:
		length = l2 - l1
		l2 += 1
	else:
		l1 += 1
		l2 = l1 + length + 1
print(length)


N = int(input())
S = input()
MOD = 2 ** 61 - 1
root = 10000
rhs = [0]
for h in map(ord, S):
	rhs.append((root * rhs[-1] + h) % MOD)
pws = [1]
for i in range(N):
	pws.append(pws[-1] * root % MOD)
ok = 0
ng = N
while ng - ok > 1:
	mid = (ok + ng) // 2
	hashes = dict()
	flg = False
	for i in range(N - mid + 1):
		hashofsub = (rhs[i + mid] - rhs[i] * pws[mid]) % MOD
		if hashofsub in hashes:
			if i >= hashes[hashofsub] + mid:
				flg = True
				break
		else:
			hashes[hashofsub] = i
	if flg:
		ok = mid
	else:
		ng = mid
print(ok)


from collections import defaultdict

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

def solve(N, S):
	low = 0
	high = (N >> 1) + 1
	while high - low > 1:
		mid = high + low >> 1
		is_match = False
		m = N - mid + 1
		d = defaultdict(list)
		for i in range(0, m):
			d[S[i:i + mid]].append(i)
		for v in d.values():
			if v[-1] - v[0] >= mid:
				is_match = True
				break
		if is_match:
			low = mid
		else:
			high = mid
	return low

def __starting_point():
	inputs = read()
	outputs = solve(*inputs)
	if outputs is not None:
		print('%s' % str(outputs))
__starting_point()


N = int(input())
S = input()
ans = 0
len_s = 1
for i in range(N):
	tmp_s = S[i:i + len_s]
	while tmp_s in S[i + len_s:]:
		len_s += 1
		tmp_s = S[i:i + len_s]
		ans += 1
print(ans)


N = int(input())
S = input()
j = 1
ans = 0
for i in range(N):
	s = S[i:i + j]
	while S[i + j:].find(s) != -1:
		j += 1
		s = S[i:i + j]
		ans += 1
print(ans)


n = int(input())
s = input()
a = i = j = 0
while j < n:
	t = s[i:j]
	if t in s[j:]:
		a = max(a, j - i)
		j += 1
	else:
		i += 1
print(a)


(n, s) = open(0)
a = i = j = 0
while s[j:]:
	if s[i:j] in s[j:]:
		a = max(a, j - i)
		j += 1
	else:
		i += 1
print(a)


N = int(input())
S = input()
DP = [[0] * (N + 1) for i in range(N + 1)]
ans = 0
for i in range(N):
	for j in range(N):
		if S[i] == S[j]:
			DP[i + 1][j + 1] = DP[i][j] + 1
			if j - DP[i + 1][j + 1] - i < 0:
				DP[i + 1][j + 1] = 0
print(max([max(i) for i in DP]))


def main():
	n = int(input())
	s = t = input()
	a = 0
	for i in range(n):
		c = 0
		for (v, w) in zip(s, t):
			if v == w:
				c += 1
			else:
				c = 0
			if c > i:
				break
			if c > a:
				a = c
		t = t[1:]
	print(a)
main()


(n, s) = open(0)
n = int(n)
a = i = j = 0
while j < n:
	t = s[i:j]
	if t in s[j:]:
		a = max(a, len(t))
		j += 1
	else:
		i += 1
print(a)


N = int(input())
S = input()
dp = [[0] * N for i in range(N)]
pm = 0
ans = 0
for i in range(N - 1, 0, -1):
	for j in range(i - 1, -1, -1):
		if S[i] == S[j]:
			if i < N - 1:
				dp[i][j] = min(dp[i + 1][j + 1] + 1, i - j)
			else:
				dp[i][j] = 1
		else:
			dp[i][j] = 0
		if dp[i][j] > ans:
			ans = dp[i][j]
print(ans)


n = int(input())
s = input()
mx = 0
for i in range(1, n):
	t = 0
	for j in range(n - i):
		t = t + 1 if s[j] == s[j + i] else 0
		mx = max(mx, min(i, t))
print(mx)


N = int(input())
S = input()

def check(l):
	D = []
	for i in range(N - 2 * l + 1):
		D.append(S[i:i + l])
		if S[i + l:i + 2 * l] in D:
			return True
ok = 0
ng = N // 2 + 1
while ng - ok > 1:
	m = (ok + ng) // 2
	if check(m):
		ok = m
	else:
		ng = m
print(ok)


n = int(input())
s = input()
MOD = 10 ** 18 + 7
A = 123456

def ok(l):
	rolling_hash = 0
	strings = {}
	for i in range(n):
		rolling_hash *= A
		rolling_hash += ord(s[i])
		if i - l >= 0:
			rolling_hash -= ord(s[i - l]) * pow(A, l, MOD)
		rolling_hash %= MOD
		if i < l - 1:
			continue
		if rolling_hash not in strings:
			strings[rolling_hash] = []
		strings[rolling_hash].append(i)
	for string in strings:
		if strings[string][-1] - strings[string][0] >= l:
			return True
	return False
(bottom, top) = (0, n)
while top - bottom > 1:
	mid = (top + bottom) // 2
	if ok(mid):
		bottom = mid
	else:
		top = mid
print(bottom)


n = int(input())
s = input()
res = 0
(i, j) = (0, 1)
while j < n:
	if s[i:j] in s[j:]:
		res = max(res, j - i)
		j += 1
	else:
		i += 1
	if i == j:
		i += 1
		j += 2
print(res)


n = int(input())
s = input()
a = [[0] * n for i in range(n)]
buf = 0
for i in range(n):
	for j in range(i + 1, n):
		if i == 0:
			if s[i] == s[j]:
				a[i][j] = 1
			continue
		if s[i] == s[j]:
			a[i][j] = min(j - i, a[i - 1][j - 1] + 1)
			buf = max(buf, a[i][j])
print(buf)


n = int(input())
s = input()
dp = [0 for i in range(n + 1)]
for i in range(n):
	if s[i - dp[i]:i + 1] in s[:i - dp[i]]:
		dp[i + 1] = dp[i] + 1
	else:
		dp[i + 1] = dp[i]
print(dp[n])


n = int(input())
s = input()
from collections import defaultdict

def check(l):
	d = defaultdict(lambda : -1)
	for i in range(n - l + 1):
		if d[s[i:i + l]] != -1:
			if d[s[i:i + l]] + l <= i:
				return True
		else:
			d[s[i:i + l]] = i
	return False
ok = 0
ng = len(s)
while abs(ok - ng) > 1:
	mid = (ok + ng) // 2
	if check(mid):
		ok = mid
	else:
		ng = mid
print(ok)


class RollingHash:

	def __init__(self, s):
		self.n = n = len(s)
		self.b = b = 129
		self.M = M = 2 ** 61 - 1
		(x, y) = (1, 0)
		self.f = f = [x] * (n + 1)
		self.h = h = [y] * (n + 1)
		for (i, c) in enumerate(s.encode()):
			f[i + 1] = x = x * b % M
			h[i + 1] = y = (y * b + c) % M

	def get(self, l, r):
		return (self.h[r] - self.h[l] * self.f[r - l]) % self.M

def main():
	n = int(input())
	s = RollingHash(input())
	(ok, ng) = (0, n)
	while ng - ok > 1:
		mid = ok + ng >> 1
		d = {}
		for i in range(0, n - mid + 1):
			k = s.get(i, i + mid)
			if k in d:
				if d[k] + mid <= i:
					ok = mid
					break
			else:
				d[k] = i
		else:
			ng = mid
	print(ok)
main()


N = int(input())
S = input()
ans = 0
for i in range(1, N):
	ct = 0
	ansa = 0
	for j in range(N - i):
		if S[j] == S[j + i]:
			ct += 1
			ansa = max(ct, ansa)
		else:
			ct = 0
	ans = max(ans, min(ansa, i))
print(ans)


N = int(input())
S = input()
r = 0
i = j = 0
while j < N:
	t = S[i:j]
	if t in S[j:]:
		r = max(r, j - i)
		j += 1
	else:
		i += 1
print(r)


n = int(input())
s = input() + '_'
dp = [[0] * (n + 1) for i in range(n + 1)]
for i in range(n - 2, -1, -1):
	for j in range(n - 1, i, -1):
		if i + dp[i + 1][j + 1] >= j:
			break
		if s[i] == s[j]:
			dp[i][j] = dp[i + 1][j + 1] + 1
print(max(list(map(lambda x: max(x), dp))))


n = int(input())
s = input()
right = 0
ans = 0
for left in range(n):
	while right < n:
		word = s[left:right + 1]
		if word in s[right + 1:]:
			ans = max(ans, len(word))
		else:
			break
		right += 1
print(ans)


n = int(input())
s = input()
res = 0
dp = [[0] * (1 + n) for _ in range(n + 1)]
for i in range(n - 1, -1, -1):
	for j in range(i + 1, n):
		if s[i] == s[j]:
			dp[i][j] = dp[i + 1][j + 1] + (j - i > dp[i + 1][j + 1])
			res = max(res, dp[i][j])
print(res)


n = int(input())
s = input()
tmp = 0
for i in range(n - 1):
	for j in range(i + tmp + 1, n):
		if not s[i:j] in s[j:]:
			break
	tmp = max(tmp, j - i - 1)
print(tmp)


from typing import List, Tuple

class RollingHash:
	__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._power) = self._build(source)

	def _build(self, source: str) -> Tuple[List[int], List[int]]:
		length = len(source)
		(hash_, power) = ([0] * (length + 1), [0] * (length + 1))
		power[0] = 1
		for (i, c) in enumerate(source, 1):
			hash_[i] = (hash_[i - 1] * self._base + ord(c)) % self._mod
			power[i] = power[i - 1] * self._base % self._mod
		return (hash_, power)

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

def 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
		else:
			ng = mid
	print(ok)

def __starting_point():
	abc141_e()
__starting_point()


import sys

def input():
	return sys.stdin.readline().rstrip()

def is_ok(arg, S):
	dic = {}
	ans = False
	for i in range(len(S) - arg + 1):
		c = S[i:i + arg]
		if c in dic:
			if i - dic[c] >= arg:
				ans = True
				break
		else:
			dic[c] = i
	return ans

def meguru_bisect(ng, ok, S):
	while abs(ok - ng) > 1:
		mid = (ok + ng) // 2
		if is_ok(mid, S):
			ok = mid
		else:
			ng = mid
	return ok

def main():
	N = int(input())
	S = input()
	print(meguru_bisect(N // 2 + 1, -1, S))

def __starting_point():
	main()
__starting_point()


import sys
sys.setrecursionlimit(10 ** 7)
rl = sys.stdin.readline

class RollingHash:

	def __init__(self, s: str, base=1007, mod=10 ** 9 + 7):
		self.mod = mod
		length = len(s)
		self.pw = [1] * (length + 1)
		self.h = [0] * (length + 1)
		v = 0
		for i in range(length):
			self.h[i + 1] = v = (v * base + ord(s[i])) % mod
		v = 1
		for i in range(length):
			self.pw[i + 1] = v = v * base % mod

	def query(self, left, right):
		return (self.h[right] - self.h[left] * self.pw[right - left]) % self.mod

def solve():
	N = int(rl())
	S = input()
	rh = RollingHash(S)

	def check(t):
		dist = dict()
		for i in range(N - t + 1):
			h = rh.query(i, i + t)
			if h in dist:
				if t <= i - dist[h]:
					return True
			else:
				dist[h] = i
		return False
	(ok, ng) = (0, N // 2 + 1)
	while 1 < ng - ok:
		mid = (ok + ng) // 2
		if check(mid):
			ok = mid
		else:
			ng = mid
	print(ok)

def __starting_point():
	solve()
__starting_point()


n = int(input())
s = input()
j = 1
result = [0]
end = n // 2 + 1
for i in range(n):
	while j < n - 1 and s[i:j] in s[:i] + '0' + s[j:]:
		j += 1
	result.append(j - i - 1)
print(max(result))


import sys
N = int(sys.stdin.readline())
S = sys.stdin.readline().strip()
ans = 0
for L in range(1, N):
	dp = [0] * N
	for x in range(N - L):
		if S[x] == S[x + L]:
			if x == 0:
				dp[x] += 1
			else:
				dp[x] = min(dp[x - 1] + 1, L)
			ans = max(ans, dp[x])
print(ans)


def main():
	N = int(input())
	S = input()
	l1 = length = 0
	l2 = 1
	while l2 + length < N:
		if S[l1:l2] in S[l2:]:
			length = l2 - l1
			l2 += 1
		else:
			l1 += 1
			l2 = l1 + length + 1
	print(length)
main()


import sys

def main():
	N = int(input())
	s = input()
	(a, i, j) = (0, 0, 1)
	while j < N:
		if s[i:j] in s[j:]:
			a = max(a, j - i)
			j += 1
		else:
			i += 1
		if i == j:
			j += 1
	print(a)

def __starting_point():
	main()
__starting_point()


N = int(input())
S = input()
maxLen = i = j = 0
while j < N:
	if j - i > N - j:
		break
	t = S[i:j]
	if t in S[j:]:
		maxLen = max(maxLen, len(t))
		j += 1
	else:
		i += 1
print(maxLen)


import itertools
N = int(input())
S = input()
dp = [[0] * N for _ in range(N)]
ans = 0
for (i, j) in itertools.combinations(range(N), 2):
	if S[i] == S[j]:
		dp[i][j] = dp[i - 1][j - 1] + 1
	else:
		dp[i][j] = 0
	ans = max(ans, min(j - i, dp[i][j]))
print(ans)


n = int(input())
s = input()
ret = 0
for l in range(n):
	while s[l:l + ret + 1] in s[l + ret + 1:]:
		ret += 1
print(ret)


n = int(input())
s = input()
r = [[0] * (n + 1) for _ in range(n + 1)]
maxV = 0
for i in range(n):
	for j in range(n):
		ii = n - 1 - i
		jj = n - 1 - j
		if s[ii] == s[jj]:
			r[ii][jj] = min(r[ii + 1][jj + 1] + 1, abs(ii - jj))
			maxV = max(maxV, r[ii][jj])
print(maxV)


from random import randint

class RollingHash:

	def __init__(self, s):
		self.base = [7073, 7577, 5445, 2742, 6972, 7547, 2267, 286, 6396, 7147, 3307, 188, 266, 8253, 2818, 9527, 5110, 1207, 4633, 6196, 309, 2646, 7533, 85, 9870, 4730, 6862, 9213, 7456, 7098, 6805, 674, 5821, 4864, 8061, 1826, 2219, 459, 5937, 5667, 9033, 5552, 7263, 2402, 9809, 3701, 7048, 2874, 8350, 6006, 973, 3317, 2522, 5546, 1669, 1545, 7972, 4979, 9905, 173, 6812, 7715, 5006, 6068, 6340, 4989, 5510, 6380, 1200, 6739, 5527, 4000, 6519, 3448, 2933, 6048, 3133, 1667, 9086, 8368, 4914, 7142, 2770, 7752, 391, 7052, 5476, 3105, 8322, 3501, 7454, 3167, 8730, 9002, 4564, 138, 2197, 7238, 3411, 7433][randint(0, 99)]
		self.mod = 4611686018427387903
		self.size = len(s)
		self.string = s
		self.hash = self.make_hashtable(s)
		self.pow = self.make_powtable()

	def make_hashtable(self, _s):
		hashtable = [0] * (self.size + 1)
		for i in range(self.size):
			hashtable[i + 1] = (hashtable[i] * self.base + ord(_s[i])) % self.mod
		return hashtable

	def make_powtable(self):
		power = [1] * (self.size + 1)
		for i in range(self.size):
			power[i + 1] = self.base * power[i] % self.mod
		return power

	def get_hash(self, left, right):
		return (self.hash[right] - self.hash[left] * self.pow[right - left]) % self.mod

	def contain(self, a):
		m = len(a)
		if m > self.size:
			return False
		hashs = self.get_hash(0, m)
		hasha = 0
		for i in range(m):
			hasha = (hasha * self.base + ord(a[i])) % self.mod
		for i in range(self.size - m + 1):
			if hasha == hashs:
				return True
			hashs = self.get_hash(i, m + i)
		return hasha == hashs
from collections import defaultdict
(n, s) = (int(input()), input())
rh = RollingHash(s)

def check(m):
	d = defaultdict(lambda : 10000000)
	for i in range(n - m + 1):
		h = rh.get_hash(i, i + m)
		d[h] = min(d[h], i)
		if i - d[h] >= m:
			return True
	return False
(l, r) = (0, n // 2 + 1)
while l + 1 < r:
	mid = (l + r) // 2
	if check(mid):
		l = mid
	else:
		r = mid
print(l)


n = int(input())
s = input()
l = len(s)
dp = [[0] * (l + 1) for _ in range(l + 1)]
ans = 0
for (i, ei) in enumerate(s, 1):
	for (j, ej) in enumerate(s[i:], i + 1):
		if ei == ej:
			dp[i][j] = min(dp[i - 1][j - 1] + 1, j - i)
			ans = max(ans, dp[i][j])
print(ans)


class RollingHash:
	__slots__ = ['_base', '_mod', '_hash', '_power']

	def __init__(self, source: str, base: int=1007, mod: int=10 ** 9 + 7) -> None:
		self._base = base
		self._mod = mod
		self._hash = [0] * (len(source) + 1)
		self._power = [0] * (len(source) + 1)
		self._power[0] = 1
		for (i, c) in enumerate(source, 1):
			self._hash[i] = (self._hash[i - 1] * self._base + ord(c)) % self._mod
			self._power[i] = self._power[i - 1] * self._base % self._mod

	def get_hash(self, left: int, right: int) -> int:
		return (self._hash[right] - self._hash[left] * self._power[right - left]) % self._mod

def 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
		else:
			ng = mid
	print(ok)

def __starting_point():
	abc141_e()
__starting_point()


def check(x, N, S):
	candidate = set()
	for i in range(N - 2 * x + 1):
		candidate.add(S[i:i + x])
		if S[i + x:i + 2 * x] in candidate:
			return True
	return False

def main():
	n = int(input())
	s = input().rstrip()
	l = 0
	r = n
	while l < r:
		mid = (l + r + 1) // 2
		if check(mid, n, s):
			l = mid
		else:
			r = mid - 1
	print((l + r + 1) // 2)

def __starting_point():
	main()
__starting_point()


base = 27

def getnum(x):
	return ord(x) - ord('a') + 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

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(input())
s = 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:
				return True
		else:
			kumi[temp] = i
	return False
while ng - ok > 1:
	mid = (ng + ok) // 2
	if hantei(mid, rh):
		ok = mid
	else:
		ng = mid
print(ok)


N = int(input())
S = [ord(s) for s in input()]
c = 0
for i in range(1, N):
	d = 0
	for (s_j, t_j) in zip(S, S[i:]):
		if s_j == t_j:
			d += 1
		else:
			c = max(c, min(d, i))
			d = 0
	c = max(c, min(d, i))
print(c)


n = int(input())
s = input()
dp = [0] * n
j = 1
for i in range(n):
	while s[i:j] in s[j:n]:
		j += 1
	dp[i] = j - i - 1
print(max(dp))


n = int(input())
s = input().strip()
assert n == len(s)
maxlen = 0
for offset in range(1, n):
	t = s[offset:]
	d = 0
	for (a, b) in zip(s, t):
		if a == b:
			d += 1
		else:
			d = 0
		if maxlen < d and d <= offset:
			maxlen = d
print(maxlen)


N = int(input())
S = input()
sride = 1
count = 0
max_num = 0
for i in range(N - 1):
	for j in range(N - sride):
		if S[j] == S[j + sride]:
			count += 1
			max_num = max(max_num, count)
		else:
			count = 0
		if count == sride:
			break
	sride += 1
	count = 0
print(max_num)


n = int(input())
s = list(map(ord, list(input())))
for i in range(n):
	s[i] -= 97
from random import randint
roli_mod = 1370757747362922367
roli_r = randint(2, roli_mod - 2)
roli = [0]
roli_rr = 1
for i in range(n):
	roli.append((roli[-1] + roli_rr * s[i]) % roli_mod)
	roli_rr *= roli_r
	roli_rr %= roli_mod

def roli_hash(i, j):
	return (roli[j + 1] - roli[i] + roli_mod) % roli_mod * pow(roli_r, roli_mod - 1 - i, roli_mod) % roli_mod

def roli_check(i1, j1, i2, j2):
	return roli_hash(i1, j1) == roli_hash(i2, j2)
ok = 0
ng = (n + 1) // 2 + 1
while ok + 1 != ng:
	i = (ok + ng) // 2
	d = {}
	f = False
	for j in range(n - i + 1):
		h = roli_hash(j, j + i - 1)
		if h in d:
			if j - d[h] >= i:
				f = True
				break
		else:
			d[h] = j
	if f:
		ok = i
	else:
		ng = i
print(ok)


n = int(input())
s = input()
left = 0
right = 1
ans = 0
while left < n:
	s1 = s[left:right]
	s2 = s[right:]
	if s1 in s2:
		ans = max(ans, len(s1))
		right += 1
	else:
		left += 1
print(ans)


import sys
sr = lambda : sys.stdin.readline().rstrip()
ir = lambda : int(sr())
lr = lambda : list(map(int, sr().split()))
N = ir()
S = sr()

def check(x):
	candidate = set()
	for i in range(N - 2 * x + 1):
		candidate.add(S[i:i + x])
		if S[i + x:i + 2 * x] in candidate:
			return True
	return False
ok = 0
ng = N
while abs(ng - ok) > 1:
	mid = (ok + ng) // 2
	if check(mid):
		ok = mid
	else:
		ng = mid
print(ok)


N = int(input())
S = input()
ans = 0
index = 0
length = 1
while index < N - ans * 2:
	while S[index:index + length] in S[index + length:]:
		length += 1
	if ans < length - 1:
		ans = length - 1
	index += 1
print(ans)


n = int(input())
s = input()
import collections
l = 0
h = n // 2 + 1
ans = 0
while h > l + 1:
	t = (h + l) // 2
	d = collections.defaultdict(int)
	for i in range(n - t + 1):
		c = s[i:i + t]
		if d[c] == 0:
			d[c] = i + 1
		elif d[c] + t <= i + 1:
			l = t
			break
	else:
		h = t
print(l)


n = int(input())
s = input()
ans = 0
lenS = 1
for i in range(n):
	tempS = s[i:i + lenS]
	while tempS in s[i + lenS:]:
		lenS += 1
		tempS = s[i:i + lenS]
		ans += 1
print(ans)


n = int(input())
s = input()
ans = 0
i = 0
j = 1
while i < n and j <= n:
	if s[i:j] in s[j:n]:
		ans = max(j - i, ans)
		j += 1
	else:
		i += 1
		j += 1
print(ans)


N = int(input())
S = input()
ans = 0
for i in range(1, N):
	tmp = '?' * i + S
	c = 0
	m = 0
	for j in range(i, N):
		if S[j] != tmp[j]:
			c = 0
		else:
			c += 1
		m = max(m, c)
	m = min(m, i)
	ans = max(ans, m)
print(ans)


tmp = input()
my_str = input()
start = 0
end = 1
max_len = 0
while end < len(my_str):
	if my_str[start:end] in my_str[end:]:
		if end - start > max_len:
			max_len = end - start
		end += 1
	else:
		start += 1
print(max_len)


N = int(input())
S = str(input())
M = [0] * N
j = 0
for i in range(N):
	while S[i:j] in S[j:N]:
		M[i] = j - i
		j += 1
print(max(M))


N = int(input())
S = input()
ans = 0
dp = [0] * N
for i in range(N - 1):
	dp2 = dp[:]
	for j in range(i + 1, N):
		if S[i] == S[j] and j - i > dp2[j - 1]:
			dp[j] = dp2[j - 1] + 1
			ans = max(ans, dp[j])
		else:
			dp[j] = 0
print(ans)


import random
from collections import defaultdict
from itertools import accumulate
import sys
input = sys.stdin.readline
n = int(input())
s = input().rstrip()
mod = (1 << 61) - 1
base = 1000 + random.randint(0, 100)
power = [1]
for i in range(1, n):
	power.append(power[-1] * base % mod)
hvalue = [0]
for i in range(n):
	hvalue.append((hvalue[-1] + ord(s[i]) * power[i]) % mod)

def rollinghash(l, r):
	return (hvalue[r] - hvalue[l]) * power[n - r] % mod

def pun(i):
	dc = defaultdict(int)
	if i > n // 2:
		return False
	for j in range(n - i + 1):
		x = rollinghash(j, i + j)
		if dc[x]:
			rg = dc[x]
			if rg <= j:
				return True
		else:
			dc[x] = i + j
	return False
l = 0
r = n // 2 + 1
while l + 1 < r:
	mi = (l + r) // 2
	if pun(mi):
		l = mi
	else:
		r = mi
print(l)


n = int(input())
s = input()
l = 0
r = 0
ans = 0
while r < n:
	t = s[l:r]
	if t in s[r:n]:
		ans = max(ans, len(t))
		r += 1
	else:
		l += 1
print(ans)


N = int(input()) + 1
S = ' ' + input()
d = [[0] * N for _ in range(N)]
r = 0
for i in range(N):
	for j in range(i - 1, 0, -1):
		d[i][j] = d[i - 1][j - 1] + 1 if S[i] == S[j] else 0
		r = max(r, min(d[i][j], i - j))
print(r)


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):
		return (self.prefix[r] - self.power[r - l] * self.prefix[l]) % self.m

	def concat(self, h1, h2, l2):
		return (self.power[l2] * h1 + h2) % self.m

	def lcp(self, l1, r1, 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)

def __starting_point():
	inputs = read()
	outputs = solve(*inputs)
	if outputs is not None:
		print('%s' % str(outputs))
__starting_point()


N = int(input())
S = input()
(ok, ng) = (0, N + 1)
while abs(ok - ng) > 1:
	x = (ok + ng) // 2
	check = set()
	for i in range(N - x + 1):
		check.add(S[i:i + x])
		if S[i + x:i + 2 * x] in check:
			ok = x
			break
	else:
		ng = x
print(ok)


N = int(input())
S = input()
lb = 0
rb = N + 1
while rb - lb > 1:
	mid = (lb + rb) // 2
	x = 0
	for (i, s) in enumerate(S[:mid]):
		x += pow(26, i) * (ord(s) - ord('a'))
	m = pow(26, mid - 1)
	a = [x]
	for (i, s) in enumerate(S[mid:]):
		x -= ord(S[i]) - ord('a')
		x //= 26
		x += m * (ord(s) - ord('a'))
		a += [x]
	f = 0
	se = set([])
	for (i, x) in enumerate(a):
		if i >= mid:
			se.add(a[i - mid])
		if x in se:
			f = 1
			break
	if f:
		lb = mid
	else:
		rb = mid
print(lb)


N = int(input())
S = input()
ans = 0
for i in range(N):
	if N - i < ans:
		break
	if S[i + 1:].find(S[i - ans:i + 1]) >= 0:
		ans += 1
print(ans)


import random
from collections import defaultdict

def atoi(s):
	return ord(s) - ord('a') + 1
N = int(input())
S = input()
mod = (1 << 61) - 1
b = random.randint(10000, mod - 1)
l = 0
r = (N + 1) // 2 + 1
while r - l > 1:
	d = (r + l) // 2
	memo = defaultdict(int)
	isok = False
	h = 0
	t = pow(b, d, mod)
	for i in range(d):
		h = (h * b + atoi(S[i])) % mod
	memo[h] = 1
	for i in range(1, N - d + 1):
		h = (h * b + atoi(S[i + d - 1]) - t * atoi(S[i - 1])) % mod
		if not memo[h]:
			memo[h] = i + 1
		elif memo[h] and i - memo[h] + 1 >= d:
			isok = True
	if isok:
		l = d
	else:
		r = d
print(l)


n = int(input())
s = input()
(m, j) = (0, 0)
for i in range(n):
	if s[j:i + 1] in s[i + 1:]:
		m = i - j + 1
	else:
		j += 1
print(m)


n = int(input())
s = input()
ans = 0
cursor = 1
for i in range(n):
	while s[i:cursor] in s[cursor:n]:
		ans = max(ans, cursor - i)
		cursor += 1
print(ans)


n = int(input())
s = input()
ans = 0
for i in range(1, n):
	chain = 0
	for j in range(n - i):
		if s[j] == s[i + j]:
			chain += 1
			if ans < chain:
				ans = min(chain, i)
		else:
			chain = 0
print(ans)


import sys
sys.setrecursionlimit(10 ** 9)
from collections import defaultdict
N = int(input())
S = input()
if N == 2:
	if S[1] == S[0]:
		print(1)
	else:
		print(0)
	return

def hantei(mid):
	flag = False
	string = S[:mid]
	dic = defaultdict(int)
	dic[string] = -1
	for k in range(mid, N):
		string += S[k]
		string = string[1:]
		if dic[string] < 0:
			if k - mid + 2 + dic[string] >= mid:
				flag = True
				break
		else:
			dic[string] = -k + mid - 2
	if flag:
		return True
	else:
		return False
ok = N // 2 + 1
ng = 0
while ok - ng > 1:
	mid = (ok + ng) // 2
	if hantei(mid):
		ng = mid
	else:
		ok = mid
if hantei(mid):
	print(min(mid, N // 2))
else:
	print(min(ng, N // 2))


N = int(input())
S = input()

def check(l):
	D = set()
	for i in range(N - 2 * l + 1):
		D.add(S[i:i + l])
		if S[i + l:i + 2 * l] in D:
			return True
OK = 0
NG = N // 2 + 1
while abs(OK - NG) > 1:
	mid = (OK + NG) // 2
	if check(mid):
		OK = mid
	else:
		NG = mid
print(OK)


N = int(input())
S = input()
left = 0
right = 1
max_length = 0
while left < N:
	if right - left > N - right:
		break
	serch_str = S[left:right]
	if serch_str in S[right:]:
		max_length = max(max_length, len(serch_str))
		right += 1
	else:
		left += 1
print(max_length)


N = int(input())
S = input()
dp = [[0] * (N + 2) for _ in range(N + 2)]
ans = 0
for i in range(1, N):
	for d in range(1, N + 1 - i):
		if S[i - 1] == S[i - 1 + d]:
			dp[i][d] = min(d, dp[i - 1][d] + 1)
			ans = max(ans, dp[i][d])
print(ans)


n = int(input())
s = input()
m = 0
for i in range(1, n):
	(d, c) = (0, 0)
	for j in range(i, n):
		if s[j - i] == s[j]:
			c += 1
		else:
			d = max(c, d)
			c = 0
	m = min(max(c, d, m), i)
print(m)


N = int(input())
S = input()
l = 0
r = 1
ans = 0
while True:
	if l == N - 1:
		break
	while S[l:r] in S[r:]:
		r += 1
	ans = max(ans, r - l - 1)
	l += 1
	if l == r:
		r = l + 1
print(ans)


n = int(input())
s = input()
r = n // 2
l = -1
while r - l > 1:
	mid = (r + l) // 2
	d = dict()
	ok = False
	for i in range(n - mid):
		ss = s[i:i + mid + 1]
		if ss not in d:
			d[ss] = i
		elif d[ss] + mid < i:
			ok = True
	if ok:
		l = mid
	else:
		r = mid
print(r)


def main():
	n = int(input())
	s = input()
	dp = [[0] * (n + 1) for i in range(n + 1)]
	ans = 0
	for i in reversed(range(n)):
		for j in reversed(range(i + 1, n)):
			if s[i] == s[j]:
				dp[i][j] = dp[i + 1][j + 1] + 1
				ans = max(ans, min(j - i, dp[i][j]))
	print(ans)
main()


n = int(input())
s = input()
dp = [[0] * (n + 1) for _ in range(n + 1)]
ans = 0
for i in range(n):
	for j in range(n):
		if i == j:
			continue
		if s[i] == s[j]:
			dp[i + 1][j + 1] = dp[i][j] + 1
			ans = max(ans, min(abs(i - j), dp[i][j] + 1))
print(ans)


from collections import defaultdict

class RollingHash(object):

	def __init__(self, S: str, MOD: int=10 ** 9 + 7, BASE: int=10 ** 5 + 7):
		self.S = S
		self.N = N = len(S)
		self.MOD = MOD
		self.BASE = BASE
		S_arr = [ord(x) for x in S]
		POWER = [1] * (N + 1)
		HASH = [0] * (N + 1)
		(p, h) = (1, 0)
		for i in range(N):
			POWER[i + 1] = p = p * BASE % MOD
			HASH[i + 1] = h = (h * BASE + S_arr[i]) % MOD
		self.S_arr = S_arr
		self.POWER = POWER
		self.HASH = HASH

	def hash(self, l: int, r: int):
		_hash = (self.HASH[r] - self.HASH[l] * self.POWER[r - l]) % self.MOD
		return _hash

def main():
	N = int(input())
	S = input()
	MOD = 998244353
	rs = RollingHash(S, MOD=MOD, BASE=37)
	(h, p) = (rs.HASH, rs.POWER)
	(left, right) = (0, N // 2 + 1)
	D = [0] * N
	while abs(right - left) > 1:
		mid = (left + right) // 2
		hashes = set()
		L = mid
		P = p[L]
		for i in range(min(L, N - 2 * L + 1)):
			D[i] = (h[L + i] - h[i] * P) % MOD
		hashes = set()
		ok = False
		for i in range(L, N - L + 1):
			hashes.add(D[i - L])
			D[i] = v = (h[L + i] - h[i] * P) % MOD
			if v in hashes:
				ok = True
				break
		if ok:
			left = mid
		else:
			right = mid
	print(left)

def __starting_point():
	main()
__starting_point()


import numpy as np
N = int(input())
S = np.array(list(input()))

def match_length(s1, s2, m):
	x = np.zeros(len(s1) + 2, dtype=bool)
	x[1:-1] = s1 == s2
	l = max(np.diff(np.nonzero(x == 0)[0]) - 1)
	return min(m, l)
ans = 0
for i in range(1, N - 1):
	ans = max(ans, match_length(S[i:], S[:-i], i))
print(ans)


N = int(input())
S = input()
CS = S
ans = 0
for i in range(N):
	now = 0
	for j in range(N):
		if S[j] == CS[j]:
			now += 1
		else:
			ans = max(ans, min(i, now))
			now = 0
	ans = max(ans, min(i, now))
	CS = ' ' + CS
print(ans)


from sys import stdin
N = int(stdin.readline().rstrip())
S = stdin.readline().rstrip()
dp = [[0] * (N + 1) for _ in range(N + 1)]
res = 0
for i in range(1, N):
	for j in range(i):
		if S[i] == S[j]:
			dp[i][j] = dp[i - 1][j - 1] + 1
		res = max(res, min(i - j, dp[i][j]))
print(res)


N = int(input())
S = input()
ans = 0
for d in range(1, N):
	count = 0
	for i in range(N - d):
		if S[i] == S[i + d]:
			count += 1
		else:
			count = 0
		ans = max(min(count, d), ans)
print(ans)


N = int(input())
S = input()
k = 1
for i in range(N - 1):
	while True:
		if S[i:i + k] in S[i + k:]:
			k += 1
		else:
			break
print(k - 1)


N = int(input())
S = input()
ans = 0
for a in range(1, N):
	cnt = 0
	for i in range(N - a):
		if S[i + a] == S[i]:
			cnt += 1
		else:
			cnt = 0
		ans = max(ans, min(cnt, a))
print(ans)


n = int(input())
s = input()
ret = 0
for d in range(1, n - 1):
	l = 0
	for i in range(n - d):
		if s[i] == s[i + d]:
			l += 1
		else:
			l = 0
		ret = max(ret, min(l, d))
print(ret)


N = int(input())
S = input().strip()
cmax = 0
for k in range(1, N):
	X = S[:N - k]
	Y = S[k:]
	cur = 0
	cnt = 0
	for i in range(N - k):
		if X[i] != Y[i]:
			cmax = max(cmax, min(cnt, k))
			cur = i
			cnt = 0
		else:
			cnt += 1
	cmax = max(cmax, min(cnt, k))
print(cmax)


n = int(input())
s = input()
A = 1234567
MOD = 10000000000000007

def ok(length):
	rolling_hash = 0
	head = pow(A, length, MOD)
	occurence = {}
	for i in range(n):
		rolling_hash = (rolling_hash * A + ord(s[i])) % MOD
		if i - length >= 0:
			rolling_hash = (rolling_hash - head * ord(s[i - length])) % MOD
		if rolling_hash not in occurence:
			occurence[rolling_hash] = []
		occurence[rolling_hash].append(i)
	for key in occurence:
		if occurence[key][-1] - occurence[key][0] >= length:
			return True
	return False
(bottom, top) = (0, n)
while top - bottom > 1:
	mid = (top + bottom) // 2
	if ok(mid):
		bottom = mid
	else:
		top = mid
print(bottom)


def main():
	import sys
	input = sys.stdin.readline
	sys.setrecursionlimit(10 ** 7)
	from collections import Counter, deque
	from itertools import combinations, permutations, accumulate, groupby, product
	from bisect import bisect_left, bisect_right
	from heapq import heapify, heappop, heappush
	import math
	n = int(input())
	s = input().rstrip()
	(l, r) = (0, 0)
	res = 0
	while r < n:
		r += 1
		if not s[l:r] in s[r:]:
			l += 1
			res = max(res, r - l)
	print(res)

def __starting_point():
	main()
__starting_point()


n = int(input())
ss = input()
max_cnt = 0
for i in range(1, n):
	cnt = 0
	for j in range(n - i):
		if ss[j] == ss[j + i]:
			cnt += 1
			max_cnt = max(cnt, max_cnt)
			if cnt == i:
				break
		else:
			cnt = 0
print(max_cnt)