import java.util.*

fun main(args: Array<String>) {
    val n = readLine()!!.toInt()
    val s = readLine()!!

    var low = 0
    var high = n / 2 + 1
    while (high - low > 1) {
        val mid = low + (high - low) / 2
        if (solve(s, mid)) {
            low = mid
        } else {
            high = mid
        }
    }
    println(low)
}

fun solve(s: String, divide: Int): Boolean {
    fun String.window(windowSize: Int, step: Int = 1): List<String> {
        val n = (length - windowSize) / step + 1
        return (0 until n).map { substring(step * it, step * it + windowSize) }
    }
    fun <T> Iterable<T>.duplicate(): Set<T> {
        val set = HashSet<T>()
        val duplicateSet = HashSet<T>()
        this.forEach {
            if(set.contains(it)) {
                duplicateSet.add(it)
            } else {
                set.add(it)
            }
        }
        return duplicateSet
    }

    val windowed = s.window(divide).duplicate()
    return windowed.any {
        s.indexOf(it) + it.length <= s.lastIndexOf(it)
    }
}