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 Common Lisp (SBCL 1.1.14) (judge verdict: Wrong Answer)

;; -*- coding: utf-8 -*-
(eval-when (:compile-toplevel :load-toplevel :execute)
  (sb-int:defconstant-eqx OPT
    #+swank '(optimize (speed 3) (safety 2))
    #-swank '(optimize (speed 3) (safety 0) (debug 0))
    #'equal)
  #+swank (ql:quickload '(:cl-debug-print :fiveam) :silent t)
  #-swank (set-dispatch-macro-character
           #\# #\> (lambda (s c p) (declare (ignore c p)) (read s nil nil t))))
#+swank (cl-syntax:use-syntax cl-debug-print:debug-print-syntax)
#-swank (disable-debugger) ; for CS Academy

;; BEGIN_INSERTED_CONTENTS
;;;
;;; double-ended queue (ring buffer)
;;;

(define-condition deque-empty-error (simple-error)
  ((queue :initarg :queue :reader deque-empty-error-queue))
  (:report
   (lambda (condition stream)
     (format stream "Attempted to pop empty deque ~W" (deque-empty-error-queue condition)))))

(define-condition deque-full-error (simple-error)
  ((queue :initarg :queue :reader deque-full-error-queue)
   (item :initarg :item :reader deque-full-error-item))
  (:report
   (lambda (condition stream)
     (format stream "Attempted to push item ~W to full deque ~W"
             (deque-full-error-item condition)
             (deque-full-error-queue condition)))))

(define-condition deque-invalid-index-error (simple-error)
  ((queue :initarg :queue :reader deque-invalid-index-error-queue)
   (index :initarg :index :reader deque-invalid-index-error-index))
  (:report
   (lambda (condition stream)
     (format stream "Invalid index ~W for ~W."
             (deque-invalid-index-error-index condition)
             (deque-invalid-index-error-queue condition)))))

;; TODO: detailed documentation
(defmacro define-deque (name &key (element-type 'fixnum))
  "Defines deque for given ELEMENT-TYPE.

constructor: MAKE-<NAME>.
basic operations: <NAME>-PUSH-FRONT, <NAME>-PUSH-BACK, <NAME>-POP-FRONT,
<NAME>-POP-BACK.
accessor: <NAME>-REF.
utilities: <NAME>-EMPTY-P, <NAME>-REINITIALIZE.
"
  (let ((push-front (intern (format nil "~A-PUSH-FRONT" name)))
        (push-back (intern (format nil "~A-PUSH-BACK" name)))
        (pop-front (intern (format nil "~A-POP-FRONT" name)))
        (pop-back (intern (format nil "~A-POP-BACK" name)))
        (empty-p (intern (format nil "~A-EMPTY-P" name)))
        (constructor (intern (format nil "MAKE-~A" name)))
        (reinitializer (intern (format nil "~A-REINITIALIZE" name)))
        (reffer (intern (format nil "~A-REF" name)))
        (data-getter (intern (format nil "~A-DATA" name)))
        (front-getter (intern (format nil "~A-FRONT" name)))
        (count-getter (intern (format nil "~A-COUNT" name))))
    `(progn
       (defstruct (,name (:constructor ,constructor
                             (size &aux
                                   (data (progn
                                           (check-type size (integer 0))
                                           (make-array (+ 1 size) :element-type ',element-type)))))
                         (:copier nil)
                         (:predicate nil))
         (data nil :type (simple-array ,element-type (*)))
         (front 0 :type (integer 0 #.most-positive-fixnum))
         (count 0 :type (integer 0 #.most-positive-fixnum)))

       (declaim (inline ,push-front))
       (defun ,push-front (obj ,name)
         (symbol-macrolet ((front (,front-getter ,name))
                           (count (,count-getter ,name)))
           (let* ((data (,data-getter ,name))
                  (length (length data))
                  (next (- front 1)))
             (declare ((integer -1 #.most-positive-fixnum) next))
             (when (< next 0) (incf next length))
             (when (= (+ 1 count) length)
               (error 'deque-full-error :item obj :queue ,name))
             (setf (aref data front) obj)
             (setq front next)
             (incf count)
             ,name)))

       (declaim (inline ,pop-front))
       (defun ,pop-front (,name)
         (symbol-macrolet ((front (,front-getter ,name))
                           (count (,count-getter ,name)))
           (let* ((data (,data-getter ,name))
                  (length (length data))
                  (next (+ front 1)))
             (declare ((integer 0 #.most-positive-fixnum) next))
             (when (= next length) (decf next length))
             (when (zerop count)
               (error 'deque-empty-error :queue ,name))
             (setq front next)
             (decf count)
             (aref data next))))

       (declaim (inline ,push-back))
       (defun ,push-back (obj ,name)
         (symbol-macrolet ((front (,front-getter ,name))
                           (count (,count-getter ,name)))
           (let* ((data (,data-getter ,name))
                  (length (length data))
                  (pos (+ front count 1)))
             (declare ((integer 0 #.most-positive-fixnum) pos))
             (when (>= pos length) (decf pos length))
             (when (= (+ 1 count) length)
               (error 'deque-full-error :item obj :queue ,name))
             (setf (aref data pos) obj)
             (incf count)
             ,name)))

       (declaim (inline ,pop-back))
       (defun ,pop-back (,name)
         (symbol-macrolet ((front (,front-getter ,name))
                           (count (,count-getter ,name)))
           (let* ((data (,data-getter ,name))
                  (length (length data))
                  (pos (+ front count)))
             (declare ((integer 0 #.most-positive-fixnum) pos))
             (when (>= pos length) (decf pos length))
             (when (zerop count)
               (error 'deque-empty-error :queue ,name))
             (prog1 (aref data pos)
               (decf count)))))

       (declaim (inline ,empty-p))
       (defun ,empty-p (,name)
         (zerop (,count-getter ,name)))

       (declaim (inline ,reinitializer))
       (defun ,reinitializer (,name)
         (setf (,count-getter ,name) 0))

       (declaim (inline ,reffer))
       (defun ,reffer (,name index)
         "Returns the INDEX-th element from the top. (0-based)"
         (declare ((integer 0 #.most-positive-fixnum) index))
         (let* ((data (,data-getter ,name))
                (count (,count-getter ,name))
                (front (,front-getter ,name))
                (length (length data))
                (pos (+ front index 1)))
           (declare ((integer 0 #.most-positive-fixnum) pos))
           (when (>= pos length) (decf pos length))
           (when (>= index count)
             (error 'deque-invalid-index-error :index index :queue ,name))
           (aref data pos))))))

(define-deque deque :element-type fixnum)

;;;
;;; Rolling hash (32-bit)
;;; NOTE: 32-bit doesn't suffice especially when the strong collision resistance
;;; is required. Better to use 62-bit version instead.
;;;

(defstruct (rhash (:constructor %make-rhash (modulus base cumul powers)))
  (modulus 4294967291 :type (unsigned-byte 32))
  (base 2095716802 :type (unsigned-byte 32))
  (cumul nil :type (simple-array (unsigned-byte 32) (*)))
  (powers nil :type (simple-array (unsigned-byte 32) (*))))

(declaim (inline make-rhash))
(defun make-rhash (vector modulus &key (key #'char-code) base)
  "Returns the table of rolling-hash of VECTOR modulo MODULUS. KEY is applied to
  each element of VECTOR prior to computing the hash value.

MODULUS := unsigned 32-bit prime number
BASE := 1 | 2 | ... | MODULUS - 1
KEY := function returning FIXNUM"
  (declare (vector vector)
           ((unsigned-byte 32) modulus)
           ((or null (unsigned-byte 32)) base)
           (function key))
  #+sbcl (assert (sb-int:positive-primep modulus))
  (let* ((base (or base (+ 1 (random (- modulus 1)))))
         (size (length vector))
         (cumul (make-array (+ 1 size) :element-type '(unsigned-byte 32)))
         (powers (make-array (+ 1 size) :element-type '(unsigned-byte 32))))
    (assert (<= 1 base (- modulus 1)))
    (setf (aref powers 0) 1)
    (dotimes (i size)
      (setf (aref powers (+ i 1))
            (mod (* (aref powers i) base) modulus))
      (let ((sum (+ (mod (* (aref cumul i) base) modulus)
                    (mod (the fixnum (funcall key (aref vector i))) modulus))))
        (setf (aref cumul (+ i 1))
              (if (> sum modulus)
                  (- sum modulus)
                  sum))))
    (%make-rhash modulus base cumul powers)))

(declaim (inline rhash-query)
         (ftype (function * (values (unsigned-byte 32) &optional)) rhash-query))
(defun rhash-query (rhash l r)
  "Returns the hash value of the interval [L, R)."
  (declare ((integer 0 #.most-positive-fixnum) l r))
  (let ((cumul (rhash-cumul rhash))
        (powers (rhash-powers rhash))
        (modulus (rhash-modulus rhash)))
    (let ((res (+ (aref cumul r)
                  (- modulus (mod (* (aref cumul l) (aref powers (- r l))) modulus)))))
      (if (> res modulus)
          (- res modulus)
          res))))

(declaim (inline rhash-concat))
(defun rhash-concat (rhash hash1 hash2 hash2-length)
  (declare ((unsigned-byte 32) hash1 hash2)
           ((integer 0 #.most-positive-fixnum) hash2-length))
  (let* ((modulus (rhash-modulus rhash)))
    (mod (+ hash2
            (* hash1 (aref (rhash-powers rhash) hash2-length)))
         modulus)))

(declaim (ftype (function * (values (unsigned-byte 32) &optional)) rhash-vector-hash)
         (inline rhash-vector-hash))
(defun rhash-vector-hash (rhash vector &key (key #'char-code))
  "Returns the hash code of VECTOR w.r.t. the moduli and bases of RHASH."
  (declare (vector vector))
  (let* ((mod (rhash-modulus rhash))
         (base (rhash-base rhash))
         (size (length vector))
         (result 0))
    (declare ((unsigned-byte 32) result))
    (dotimes (i size)
      ;; (2^32-1) * (2^32-1) + (2^32-1) < 2^64
      (setq result (mod (+ (* base result)
                           (the (unsigned-byte 32)
                                (mod (the fixnum (funcall key (aref vector i))) mod)))
                        mod)))
    result))

(defun rhash-get-lcp (rhash1 start1 rhash2 start2)
  (declare #.OPT
           ((mod #.most-positive-fixnum) start1 start2))
  (let ((max-length (min (- (length (rhash-cumul rhash1)) start1 1)
                         (- (length (rhash-cumul rhash2)) start2 1))))
    (declare (optimize (safety 0)))
    (labels ((bisect (ok ng)
               (declare ((integer 0 #.most-positive-fixnum) ok ng))
               (if (<= (- ng ok) 1)
                   ok
                   (let ((mid (ash (+ ng ok) -1)))
                     (if (= (rhash-query rhash1 start1 (+ start1 mid))
                            (rhash-query rhash2 start2 (+ start2 mid)))
                         (bisect mid ng)
                         (bisect ok mid))))))
      (bisect 0 (+ 1 max-length)))))

(declaim (inline read-line-into))
(defun read-line-into (buffer-string &key (in *standard-input*) (term-char #\Space))
  "Receives ASCII inputs and returns multiple values: the string and the end
position.

This function calls READ-BYTE to read characters though it calls READ-CHAR
instead on SLIME because SLIME's IO is not bivalent."
  (declare (inline read-byte)) ; declaring (sb-kernel:ansi-stream in) will be faster
  (loop for c of-type base-char =
           #-swank (code-char (read-byte in nil #.(char-code #\Newline)))
           #+swank (read-char in nil #\Newline)
        for idx from 0
        until (char= c #\Newline)
        do (setf (char buffer-string idx) c)
        finally (when (< idx (length buffer-string))
                  (setf (char buffer-string idx) term-char))
                (return (values buffer-string idx))))

(defmacro dbg (&rest forms)
  #+swank
  (if (= (length forms) 1)
      `(format *error-output* "~A => ~A~%" ',(car forms) ,(car forms))
      `(format *error-output* "~A => ~A~%" ',forms `(,,@forms)))
  #-swank (declare (ignore forms)))

(defmacro define-int-types (&rest bits)
  `(progn
     ,@(mapcar (lambda (b) `(deftype ,(intern (format nil "UINT~A" b)) () '(unsigned-byte ,b))) bits)
     ,@(mapcar (lambda (b) `(deftype ,(intern (format nil "INT~A" b)) () '(signed-byte ,b))) bits)))
(define-int-types 2 4 7 8 15 16 31 32 62 63 64)

(declaim (inline println))
(defun println (obj &optional (stream *standard-output*))
  (let ((*read-default-float-format* 'double-float))
    (prog1 (princ obj stream) (terpri stream))))

(defconstant +mod+ 1000000007)

;;;
;;; Body
;;;

(defun main ()
  (declare #.OPT)
  (let* ((n (read))
         (s (make-string n :element-type 'base-char)))
    (read-line-into s)
    (let ((rhash (make-rhash s 4294967291 :base 2095716802)))
      (labels ((feasible-p (len)
                 (declare (uint62 len))
                 (let ((q (make-deque (+ len 1)))
                       (table (make-hash-table :test #'eq)))
                   (loop for start from 0 to (- n len)
                         for value = (rhash-query rhash start (+ start len))
                         do (deque-push-back value q)
                            (when (> (deque-count q) len)
                              (setf (gethash (deque-pop-front q) table) t))
                            (when (gethash value table)
                              (return-from feasible-p t))
                         finally (return nil)))))
        (sb-int:named-let bisect ((ok 0) (ng n))
          (if (<= (- ng ok) 1)
              (println ok)
              (let ((mid (ash (+ ok ng) -1)))
                (if (feasible-p mid)
                    (bisect mid ng)
                    (bisect ok mid)))))))))

#-swank (main)

;;;
;;; Test and benchmark
;;;

#+swank
(defun io-equal (in-string out-string &key (function #'main) (test #'equal))
  "Passes IN-STRING to *STANDARD-INPUT*, executes FUNCTION, and returns true if
the string output to *STANDARD-OUTPUT* is equal to OUT-STRING."
  (labels ((ensure-last-lf (s)
             (if (eql (uiop:last-char s) #\Linefeed)
                 s
                 (uiop:strcat s uiop:+lf+))))
    (funcall test
             (ensure-last-lf out-string)
             (with-output-to-string (out)
               (let ((*standard-output* out))
                 (with-input-from-string (*standard-input* (ensure-last-lf in-string))
                   (funcall function)))))))

#+swank
(defun get-clipbrd ()
  (with-output-to-string (out)
    (run-program "C:/msys64/usr/bin/cat.exe" '("/dev/clipboard") :output out)))

#+swank (defparameter *this-pathname* (uiop:current-lisp-file-pathname))
#+swank (defparameter *dat-pathname* (uiop:merge-pathnames* "test.dat" *this-pathname*))

#+swank
(defun run (&optional thing (out *standard-output*))
  "THING := null | string | symbol | pathname

null: run #'MAIN using the text on clipboard as input.
string: run #'MAIN using the string as input.
symbol: alias of FIVEAM:RUN!.
pathname: run #'MAIN using the text file as input."
  (let ((*standard-output* out))
    (etypecase thing
      (null
       (with-input-from-string (*standard-input* (delete #\Return (get-clipbrd)))
         (main)))
      (string
       (with-input-from-string (*standard-input* (delete #\Return thing))
         (main)))
      (symbol (5am:run! thing))
      (pathname
       (with-open-file (*standard-input* thing)
         (main))))))

#+swank
(defun gen-dat ()
  (uiop:with-output-file (out *dat-pathname* :if-exists :supersede)
    (format out "")))

#+swank
(defun bench (&optional (out (make-broadcast-stream)))
  (time (run *dat-pathname* out)))

;; To run: (5am:run! :sample)
#+swank
(it.bese.fiveam:test :sample
  (it.bese.fiveam:is
   (common-lisp-user::io-equal "5
ababa
"
    "2
"))
  (it.bese.fiveam:is
   (common-lisp-user::io-equal "2
xy
"
    "0
"))
  (it.bese.fiveam:is
   (common-lisp-user::io-equal "13
strangeorange
"
    "5
")))