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.15.1) (judge verdict: Time Limit Exceeded)

use std::collections::HashMap;
fn solve() {
    let s = std::io::stdin();
    let mut sc = Scanner { stdin: s.lock() };
    let n: usize = sc.read();
    let s: Vec<char> = sc.chars();
    let s = s.as_slice();
    let mut string_to_pos = HashMap::new();

    let seq: Vec<u64> = s.iter().map(|&c| c as u64).collect();
    let rh = rolling_hash::RollingHash::new(&seq);

    for i in 0..n {
        for j in i + 1..n {
            // let t = &s[i..j + 1].iter().cloned().collect::<String>();
            let t = rh.hash(i, j);
            string_to_pos.entry(t.clone()).or_insert(vec![]);
            string_to_pos.get_mut(&t).unwrap().push((i, j));
        }
    }
    let mut result = 0;
    for (st, pos) in string_to_pos.iter() {
        let (mut left, mut right) = pos[0];
        for i in 1..pos.len() {
            let (l, r) = pos[i];
            if right < l || r < left {
                result = std::cmp::max(result, r - l + 1);
                break;
            }
            right = std::cmp::min(right, r);
            left = std::cmp::max(left, l);
        }
    }
    println!("{}", result);
}

fn main() {
    std::thread::Builder::new()
        .stack_size(64 * 1024 * 1024) // 64MB
        .spawn(|| solve())
        .unwrap()
        .join()
        .unwrap();
}
pub mod rolling_hash {
    const MASK_SIZE: usize = 2;
    static MOD: [u64; MASK_SIZE] = [999999937u64, 1000000007u64];
    const BASE: u64 = 9973;
    pub struct RollingHash {
        hash: Vec<Vec<u64>>,
        pow: Vec<Vec<u64>>,
    }

    impl RollingHash {
        pub fn new(s: &[u64]) -> RollingHash {
            let n = s.len();
            let mut hash: Vec<Vec<u64>> = vec![vec![0u64; n + 1]; 2];
            let mut pow: Vec<Vec<u64>> = vec![vec![0u64; n + 1]; 2];
            for i in 0..MASK_SIZE {
                pow[i][0] = 1;
                for j in 0..n {
                    pow[i][j + 1] = pow[i][j] * BASE % MOD[i];
                    hash[i][j + 1] = (hash[i][j] * BASE + s[j]) % MOD[i];
                }
            }
            RollingHash {
                hash: hash,
                pow: pow,
            }
        }

        //[l, r)
        pub fn hash1(&self, l: usize, r: usize) -> u64 {
            (self.hash[0][r] + MOD[0] - self.hash[0][l] * self.pow[0][r - l] % MOD[0]) % MOD[0]
        }
        //[l, r)
        pub fn hash2(&self, l: usize, r: usize) -> u64 {
            (self.hash[1][r] + MOD[1] - self.hash[1][l] * self.pow[1][r - l] % MOD[1]) % MOD[1]
        }
        //[l, r)
        pub fn hash(&self, l: usize, r: usize) -> (u64, u64) {
            (self.hash1(l, r), self.hash2(l, r))
        }
        pub fn equal(&self, l1: usize, r1: usize, l2: usize, r2: usize) -> bool {
            self.hash1(l1, r1) == self.hash1(l2, r2) && self.hash2(l1, r1) == self.hash2(l2, r2)
        }
    }
}

//snippet from kenkoooo
pub struct Scanner<R> {
    stdin: R,
}

impl<R: std::io::Read> Scanner<R> {
    pub fn read<T: std::str::FromStr>(&mut self) -> T {
        use std::io::Read;
        let buf = self
            .stdin
            .by_ref()
            .bytes()
            .map(|b| b.unwrap())
            .skip_while(|&b| b == b' ' || b == b'\n' || b == b'\r')
            .take_while(|&b| b != b' ' && b != b'\n' && b != b'\r')
            .collect::<Vec<_>>();
        unsafe { std::str::from_utf8_unchecked(&buf) }
            .parse()
            .ok()
            .expect("Parse error.")
    }
    pub fn read_line(&mut self) -> String {
        use std::io::Read;
        let buf = self
            .stdin
            .by_ref()
            .bytes()
            .map(|b| b.unwrap())
            .skip_while(|&b| b == b'\n' || b == b'\r')
            .take_while(|&b| b != b'\n' && b != b'\r')
            .collect::<Vec<_>>();
        unsafe { std::str::from_utf8_unchecked(&buf) }
            .parse()
            .ok()
            .expect("Parse error.")
    }
    pub fn vec<T: std::str::FromStr>(&mut self, n: usize) -> Vec<T> {
        (0..n).map(|_| self.read()).collect()
    }

    pub fn chars(&mut self) -> Vec<char> {
        self.read::<String>().chars().collect()
    }
}