import std.algorithm;
import std.bigint;
import std.concurrency;
import std.container;
import std.conv;
import std.functional;
import std.format;
import std.math;
import std.meta;
import std.numeric;
import std.random;
import std.range;
import std.stdio;
import std.string;
import std.traits;
import std.typecons;


auto solve(long N, string S) {
    long ans;
    foreach (l; 0 .. N) foreach (i, v; zAlgorithm(S[l .. $])) {
        auto r = l + i;
        ans = ans.max(min(r - l, N - r, v));
    }
    return ans;
}


long[] zAlgorithm(R)(R range) if (isSomeString!R || isRandomAccessRange!R) {
    const length = range.length;
    auto lens = new long[](length);
    
    long c;
    foreach (r; 1 .. cast(long) length) {
        if (r + lens[r - c] < c + lens[c]) {
            lens[r] = lens[r - c];
        } else {
            long len = max(0, c + lens[c] - r);
            while (r + len < length && range[len] == range[r + len])
                ++len;
            lens[r] = len;
            c = r;
        }
    }

    lens[0] = length;
    return lens;
}


void main() {
    auto input = stdin.byLine.map!split.joiner;

    long N;
    N = input.front.to!long;
    input.popFront;

    string S;
    S = input.front.to!string;
    input.popFront;

    static if (is(ReturnType!solve == void))
        solve(N, S);
    else
        solve(N, S).writeln;
}
