Problem:
Score : 500 points

Problem Statement

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 1

5
ababa

Sample Output 1

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.

Sample Input 2

2
xy

Sample Output 2

0

No non-empty string satisfies the conditions.

Sample Input 3

13
strangeorange

Sample Output 3

5

Solution in Rust (1.42.0) (judge verdict: Accepted)

use proconio::input;
use proconio::marker::Bytes;
use std::collections::HashMap;

type i64 = i128;
const A:i64 = 1e5 as i64 +2;
const M:i64 = 1e18 as i64 +9;
fn main(){
    input! {
        n:usize,
        s:Bytes
    };
    
    let mut lb = 0;
    let mut ub = n+1;

    while ub-lb>1 {
        let mid = (lb+ub)/2;

        let mut fnd = false;

        let mut sum = 0;
        let mut am =1;
        for i in 0..(mid-1) {
            sum = (sum*A+(s[i] as i64))%M;
            am = am*A%M;
        }
        let am = am;

        let mut hm:HashMap<i64,usize> = HashMap::new();
        for i in (mid-1)..n {
            sum = (sum*A+(s[i] as i64))%M;
            if hm.contains_key(&sum) {
                fnd = fnd || i-hm[&sum]>=mid;
            }
            hm.entry(sum).or_insert(i);
            sum = ((sum - am*(s[i-(mid-1)] as i64))%M+M)%M;
        }

        if fnd {
            lb=mid;
        } else {
            ub=mid;
        }
    }
    println!("{}",lb);
}