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: Wrong Answer)

#![allow(unused_parens)]
#![allow(unused_imports)]
#![allow(non_upper_case_globals)]


macro_rules! input {
    (source = $s:expr, $($r:tt)*) => {
        let mut iter = $s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
    ($($r:tt)*) => {
        let mut s = {
            use std::io::Read;
            let mut s = String::new();
            std::io::stdin().read_to_string(&mut s).unwrap();
            s
        };
        let mut iter = s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
}

macro_rules! input_inner {
    ($iter:expr) => {};
    ($iter:expr, ) => {};

    ($iter:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($iter, $t);
        input_inner!{$iter $($r)*}
    };
}

macro_rules! read_value {
    ($iter:expr, ( $($t:tt),* )) => {
        ( $(read_value!($iter, $t)),* )
    };

    ($iter:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($iter, $t)).collect::<Vec<_>>()
    };

    ($next:expr, [$t:tt]) => {
        {
            let len = read_value!($next, usize);
            (0..len).map(|_| read_value!($next, $t)).collect::<Vec<_>>()
        }
    };
    ($iter:expr, chars) => {
        read_value!($iter, String).chars().collect::<Vec<char>>()
    };

    ($iter:expr, usize1) => {
        read_value!($iter, usize) - 1
    };

    ($iter:expr, $t:ty) => {
        $iter.next().unwrap().parse::<$t>().expect("Parse error")
    };
}


#[cfg(debug_assertions)]
macro_rules! mydbg {
    //($arg:expr) => (dbg!($arg))
    ($arg:expr) => (println!("{:?}",$arg));
}


#[cfg(not(debug_assertions))]
macro_rules! mydbg {
    ($($arg:expr),*) => {};
}


use std::cmp;
use std::collections::HashMap;

use std::cell::{RefCell,Cell};
use std::rc::Rc;

pub struct SuffixArray{
    sa : Rc<RefCell<Vec<usize>>>,
    rank : Vec<i32>,
    chars : Vec<char>,
    length : usize,
    tmp : Rc<RefCell<Vec<i32>>>,
    k : Rc<Cell<usize>>,
    lcp_a : Vec<i32>,

}

impl SuffixArray{
    pub fn new(s:String)->Self{
        let n = s.len();
        let c = s.chars().collect::<Vec<char>>();
        let mut rank = vec![0;n+1];
        let mut tmp = Rc::new(RefCell::new(vec![0;n+1]));
        let mut sa :Rc<RefCell<Vec<usize>>> = Rc::new(RefCell::new(vec![0;n+1]));
        let mut k = Rc::new(Cell::new(1));
        let mut lcp = vec![0;n];


        return SuffixArray{
            sa:sa,
            length:n,
            rank:rank,
            tmp:tmp,
            chars:c,
            k:k,
            lcp_a:lcp,
        };
    }

    pub fn compare_sa2 (&mut self,i: usize,j : usize) -> std::cmp::Ordering{
        let ii = i as usize;
        let jj = j as usize;
        if(self.rank[ii] != self.rank[jj]){
            if(self.rank[ii] < self.rank[jj]){return std::cmp::Ordering::Less}
            else if(self.rank[ii] == self.rank[jj]){return std::cmp::Ordering::Equal}
            else {std::cmp::Ordering::Greater}
        }
        else{
            let i2 = if(ii+self.k.get() >self.length ) { -1} else { self.rank[ii+self.k.get()]};
            let j2 = if(jj+self.k.get() >self.length ) { -1} else { self.rank[jj+self.k.get()]};
            if(i2<j2){return std::cmp::Ordering::Less}
            else if(i2==j2){return std::cmp::Ordering::Equal}
            else {std::cmp::Ordering::Greater}
        }
    }

    #[macro_use]
    pub fn contain(&mut self , target : String)->bool{
        let mut a = 0;
        let mut b = self.length;
        let mut flag = 0;
        let target_c = target.chars().collect::<Vec<char>>();
        let mut index=0;
        while (b-a>=1){
            index+=1;
            if(index>1000){
                break;
            }
            let c = (b+a)/2;
            let sa_c = self.sa.borrow()[c];
            for i in sa_c..(sa_c+target.len()) {                                
                if(self.chars.len() <= i) {
                    flag = -1;
                    break
                };
                if(self.chars[i] != target_c[i-(sa_c as usize)]){
                    flag = self.chars[i] as i32 - target_c[i-(sa_c as usize)] as i32;
                    break;
                }
            }

            if(flag >= 0){
                b=c;
            }
            else{
                a=c;
            }

        }

        
        let sa_b = self.sa.borrow()[b];
        flag = 0;
        for i in sa_b..(sa_b+target.len()) {
            if(self.chars.len() <= i) {
                flag = -1;
                break
            };
            if(self.chars[i] != target_c[i-(sa_b as usize)]){
                flag = self.chars[i] as i32 - target_c[i-(sa_b as usize)] as i32;
                break;
            }
        }
        return if(flag == 0){true} else {false};

    }

    pub fn gen_lcp(&mut self){
        let n  = self.length;
        self.lcp_a[0] = 0;
        for i in 0..n+1{
           self.rank[self.sa.borrow()[i]] = i as i32;
        }

        let mut h = 0;
        for i in 0..n{
            let j = self.sa.borrow()[(self.rank[i]-1) as usize];
            if h>0 {h-=1};
            while(true){
                if(j+h >=n) {break;}
                if(i+h >=n) {break;}
                if self.chars[i+h] != self.chars[j+h] { break;}

                h+=1;
            }

            self.lcp_a[(self.rank[i]-1) as usize]=h as i32;
        }

    }




    pub fn gen(&mut self){
        
        for i in 0..&self.length+1{
            self.sa.borrow_mut()[i] = i;
            self.rank[i] = if i<self.length {self.chars[i] as i32} else {-1};
        }
        
        

        
        while(true){
            if(self.k.get()>self.length) {break};
            
            {
                self.sa.borrow_mut().sort_by(|i,j| -> std::cmp::Ordering{
                let ii = *i as usize;
                let jj = *j as usize;
                if(self.rank[ii] != self.rank[jj]){
                    if(self.rank[ii] < self.rank[jj]){return std::cmp::Ordering::Less}
                    else if(self.rank[ii] == self.rank[jj]){return std::cmp::Ordering::Equal}
                    else {std::cmp::Ordering::Greater}
                }
                else{
                    let i2 = if(ii+self.k.get() >self.length ) { -1} else { self.rank[ii+self.k.get()]};
                    let j2 = if(jj+self.k.get() >self.length ) { -1} else { self.rank[jj+self.k.get()]};
                    if(i2<j2){return std::cmp::Ordering::Less}
                    else if(i2==j2){return std::cmp::Ordering::Equal}
                    else {std::cmp::Ordering::Greater}
                }
            }
);
            }
            {
            self.tmp.borrow_mut()[self.sa.borrow()[0]]=0;
            }
            for i in 1..self.length+1{                
                let a = self.sa.borrow()[i-1];
                let b = self.sa.borrow()[i];
                let fuga = self.compare_sa2(a,b);
                let hoge = if(fuga == std::cmp::Ordering::Greater || fuga == std::cmp::Ordering::Equal)  {0} else {1};
                let c = self.tmp.borrow()[self.sa.borrow()[i-1]];
                self.tmp.borrow_mut()[self.sa.borrow()[i]] = c + hoge;
            }
            for i in 0..self.length+1{
                //self.rank.borrow_mut()[i] = self.tmp.borrow()[i];
                self.rank[i] = self.tmp.borrow()[i];
            }
            self.k.set(self.k.get()*2);
        }




    }
}




use std::ops::{ Add, Sub , Div , Mul };
#[macro_use]


// #[snippet = "ComplexNum"]
pub trait Monoid {
    type T: Clone;
    fn id() -> Self::T;
    fn op(a: &Self::T, b: &Self::T) -> Self::T;
}



// #[snippet = "ComplexNum"]
pub struct SegTree<M:Monoid>{
    n :usize,
    data : Vec<M::T>,
}

impl<M:Monoid> SegTree<M>{
    pub fn new (n_ : usize) -> SegTree<M>{
        let mut n = 1 as usize;
        while(n< n_){
            n *=2;
        }
        SegTree{
            n:n,
            data:vec![M::id().clone();(2*n)],
        }

    }

    #[macro_use]
    pub fn update(&mut self , index : usize , v : M::T){
        let mut k = index + self.n-1;
        self.data[k] = v;
        while (k>0){
            k = (k-1)/2;
            self.data[k] = M::op(&self.data[2*k+1] , &self.data[2*k+2]);
        }

    }

    pub fn query(&mut self ,l:usize,r:usize)->M::T{
        let mut l = l+self.n-1;
        let mut r = r+self.n-1;
        if(l==r){
            return M::op(&M::id().clone() ,&self.data[l])
        }
        let mut ret = M::id().clone();
        while(l<r){
            if(l%2 == 0){
            //if((l&1_usize) == 0_usize){
                ret = M::op(&ret , &self.data[l]);                
            }
            if(r%2 == 0){
            //if((r&1_usize) == 0_usize){
                ret = M::op(&ret , &self.data[r-1]);
            }

            l = l/2;
            r = (r-1)/2;

        }

        return ret;

    }

}


struct MAX;
impl Monoid for MAX {
    type T = u64;
    fn id() -> Self::T {
        100100100100_u64
    }
    fn op(a: &Self::T, b: &Self::T) -> Self::T {
        return cmp::min(*a,*b);
    }
}



fn main() {

    input! { 
       n: usize,
       s : String,
    }

    let mut sa = SuffixArray::new(s);
    sa.gen();
    sa.gen_lcp();

    mydbg!(sa.sa);
    mydbg!(sa.lcp_a);

    let mut st:SegTree<MAX> = SegTree::new(sa.lcp_a.len());
    for i in 0..sa.lcp_a.len(){
        st.update(i, sa.lcp_a[i] as u64);
    }

    let mut ans = 0;

    for i in 0..sa.lcp_a.len(){
        for j in (i+1)..sa.lcp_a.len(){
            // if(i==j) {continue};
            // let a = sa.sa.borrow()[i];
            // let b = sa.sa.borrow()[j];
            // if(a==b) {continue};
            // if(a == sa.sa.borrow().len()-1 || b == sa.sa.borrow().len()-1){continue};
            // if(a>b) {continue};

            
            // let tmp  = cmp::min(st.query(a, b-1), (b-a) as u64);
            // mydbg!((st.query(a, b-1), b-a));
            let mut a = sa.sa.borrow()[i];
            let mut b = sa.sa.borrow()[j];
            
            if(a>b){
                std::mem::swap(&mut a, &mut b);
            }

            let tmp  = cmp::min(st.query(i, j-1), (b-a) as u64);
            
            
            
            ans = cmp::max(ans, tmp);
        }
    }

    println!("{}",ans);



}