Problem:
Score : 600 points

Problem Statement

There are 2N balls, N white and N black, arranged in a row. The integers from 1 through N are written on the white balls, one on each ball, and they are also written on the black balls, one on each ball.
The integer written on the i-th ball from the left (1 ≤ i ≤ 2N) is a_i, and the color of this ball is represented by a letter c_i.
c_i = W represents the ball is white; c_i = B represents the ball is black.

Takahashi the human wants to achieve the following objective:

For every pair of integers (i,j) such that 1 ≤ i < j ≤ N, the white ball with i written on it is to the left of the white ball with j written on it.

For every pair of integers (i,j) such that 1 ≤ i < j ≤ N, the black ball with i written on it is to the left of the black ball with j written on it.

In order to achieve this, he can perform the following operation:

Swap two adjacent balls.

Find the minimum number of operations required to achieve the objective.

Constraints

1 ≤ N ≤ 2000

1 ≤ a_i ≤ N

c_i = W or c_i = B.

If i ≠ j, (a_i,c_i) ≠ (a_j,c_j).

Input

Input is given from Standard Input in the following format:

N
c_1 a_1
c_2 a_2
:
c_{2N} a_{2N}

Output

Print the minimum number of operations required to achieve the objective.

Sample Input 1

3
B 1
W 2
B 3
W 1
W 3
B 2

Sample Output 1

4

The objective can be achieved in four operations, for example, as follows:

Swap the black 3 and white 1.

Swap the white 1 and white 2.

Swap the black 3 and white 3.

Swap the black 3 and black 2.

Sample Input 2

4
B 4
W 4
B 3
W 3
B 2
W 2
B 1
W 1

Sample Output 2

18

Sample Input 3

9
W 3
B 1
B 4
W 1
B 5
W 9
W 2
B 6
W 5
B 3
W 8
B 9
W 7
B 2
B 8
W 4
W 6
B 7

Sample Output 3

41

Solution in Common Lisp (SBCL 1.1.14) (judge verdict: Time Limit Exceeded)

;; -*- 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
           ;; enclose the form with VALUES to avoid being captured by LOOP macro
           #\# #\> (lambda (s c p) (declare (ignore c p)) `(values ,(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
;;;
;;; Succinct bit vector
;;;

;; REVIEW: Is it really better to use the typical three-layer succint bit vector
;; in competitive programming? It may be efficient to use a two-layer (not
;; succinct but compact) bit vector preserving the original vector and the
;; cumulative sum per 64-bit word.

(defconstant +chunk-width+ (* 64 16))
;; This constant cannot be changed as the current implementation depends on the
;; assumption: +BLOCK-WIDTH+ is equal to the word size.
(defconstant +block-width+ 64)
(defconstant +block-number+ (floor +chunk-width+ +block-width+))

(eval-when (:compile-toplevel :load-toplevel :execute)
  (assert (zerop (mod +chunk-width+ +block-width+)))
  (assert (= sb-vm:n-word-bits 64)))

(defstruct (succinct-bit-vector (:constructor %make-sucbv (storage chunks blocks))
                                (:conc-name sucbv-)
                                (:copier nil))
  (storage nil :type simple-bit-vector)
  (chunks nil :type (simple-array (integer 0 #.most-positive-fixnum) (*)))
  (blocks nil :type (simple-array (unsigned-byte 16) (* *))))

(defun make-sucbv! (vector)
  "The consequence is undefined when VECTOR is modified after a succinct bit
vector is created."
  (declare (optimize (speed 3)))
  (check-type vector simple-bit-vector)
  (let* ((vector (if (zerop (mod (length vector) +chunk-width+))
                     vector
                     (adjust-array vector
                                   (* +chunk-width+ (ceiling (length vector) +chunk-width+))
                                   :initial-element 0)))
         (len (length vector))
         (chunk-count (floor len +chunk-width+))
         (chunks (make-array (+ 1 chunk-count)
                             :element-type '(integer 0 #.most-positive-fixnum)
                             :initial-element 0))
         (blocks (make-array (list (+ 1 chunk-count) +block-number+)
                             :element-type '(unsigned-byte 16)
                             :initial-element 0))
         (sum 0))
    (declare (simple-bit-vector vector)
             ((integer 0 #.most-positive-fixnum) sum))
    (dotimes (i chunk-count)
      (setf (aref chunks i) sum)
      (let ((block-sum 0))
        (declare ((integer 0 #.most-positive-fixnum) block-sum))
        (dotimes (j +block-number+)
          (setf (aref blocks i j) block-sum)
          (incf block-sum
                (logcount (sb-kernel:%vector-raw-bits vector (+ (* i +block-number+) j)))))
        (incf sum block-sum)))
    (setf (aref chunks chunk-count) sum)
    (%make-sucbv vector chunks blocks)))

(declaim (inline sucbv-ref))
(defun sucbv-ref (sucbv index)
  (sbit (sucbv-storage sucbv) index))

;; NOTE: No error handling.
(declaim (ftype (function * (values (integer 0 #.most-positive-fixnum) &optional)) sucbv-rank))
(defun sucbv-rank (sucbv end)
  "Counts the number of 1's in the range [0, END)."
  (declare (optimize (speed 3))
           ((integer 0 #.most-positive-fixnum) end))
  (let ((storage (sucbv-storage sucbv))
        (chunks (sucbv-chunks sucbv))
        (blocks (sucbv-blocks sucbv)))
    (multiple-value-bind (cpos crem) (floor end +chunk-width+)
      (multiple-value-bind (bpos brem) (floor crem +block-width+)
        (let ((csum (aref chunks cpos))
              (bsum (aref blocks cpos bpos))
              (wordpos (floor end 64)))
          (+ csum
             bsum
             (if (zerop brem) ; avoid out-of-bounds access
                 0
                 (logcount (ldb (byte brem 0)
                                (sb-kernel:%vector-raw-bits storage wordpos))))))))))

(declaim (ftype (function * (values (integer 0 #.most-positive-fixnum) &optional)) sucbv-count))
(defun sucbv-count (sucbv value end)
  "Counts the number of VALUEs in the range [0, END)"
  (declare (optimize (speed 3))
           (bit value)
           ((integer 0 #.most-positive-fixnum) end))
  (let ((count1 (sucbv-rank sucbv end)))
    (if (= value 1)
        count1
        (- end count1))))

(defun sucbv-select (sucbv num)
  "Detects the position of (1-based) NUM-th 1 in SUCBV. (SUCBV-SELECT 0) always
returns 0."
  (declare (optimize (speed 3))
           ((integer 0 #.most-positive-fixnum) num))
  (let* ((storage (sucbv-storage sucbv))
         (chunks (sucbv-chunks sucbv))
         (blocks (sucbv-blocks sucbv))
         (chunk-size (length chunks)))
    (unless (<= num (aref chunks (- chunk-size 1)))
      ;; FIXME: introduce condition class
      (error "~&There aren't ~W 1's in ~W" num sucbv))
    (labels ((chunk-bisect (ok ng)
               (declare ((unsigned-byte 32) ok ng))
               (if (<= (- ng ok) 1)
                   ok
                   (let ((mid (ash (+ ok ng) -1)))
                     (if (<= num (aref chunks mid))
                         (chunk-bisect ok mid)
                         (chunk-bisect mid ng))))))
      (let* ((chunk-idx (chunk-bisect 0 chunk-size))
             (num (- num (aref chunks chunk-idx))))
        (labels ((block-bisect (ok ng)
                   (declare ((unsigned-byte 32) ok ng))
                   (if (<= (- ng ok) 1)
                       ok
                       (let ((mid (ash (+ ok ng) -1)))
                         (if (<= num (aref blocks chunk-idx mid))
                             (block-bisect ok mid)
                             (block-bisect mid ng))))))
          (let* ((block-idx (block-bisect 0 +block-number+))
                 (num (- num (aref blocks chunk-idx block-idx)))
                 (word-pos (+ block-idx (* chunk-idx +block-number+)))
                 (word (sb-kernel:%vector-raw-bits storage word-pos)))
            (labels ((pos-bisect (ok ng)
                       (declare ((integer 0 64) ok ng))
                       (if (<= (- ng ok) 1)
                           ok
                           (let ((mid (ash (+ ok ng) -1)))
                             (if (<= num (logcount (ldb (byte mid 0) word)))
                                 (pos-bisect ok mid)
                                 (pos-bisect mid ng))))))
              (let ((pos (pos-bisect 0 64)))
                (+ (* 64 word-pos) pos)))))))))

;;;
;;; Wavelet matrix
;;;

(deftype wavelet-integer () '(integer 0 #.most-positive-fixnum))

(defstruct (wavelet-matrix (:constructor %make-wavelet-matrix
                               (length data zeros
                                &aux (depth (array-dimension data 0))))
                           (:copier nil)
                           (:conc-name wavelet-))
  (depth 0 :type (integer 1 #.most-positive-fixnum))
  (length 0 :type (integer 0 #.most-positive-fixnum))
  (data nil :type (simple-array succinct-bit-vector (*)))
  (zeros nil :type (simple-array (integer 0 #.most-positive-fixnum) (*))))

#+sbcl
(eval-when (:compile-toplevel :load-toplevel :execute)
  (sb-c:defknown make-wavelet ((integer 1 #.most-positive-fixnum) vector)
      wavelet-matrix (sb-c:flushable)
    :overwrite-fndb-silently t))

;; TODO: add deftransform for better type derivation
(defun make-wavelet (bit-depth vector)
  (declare ((integer 1 #.most-positive-fixnum) bit-depth))
  (let* ((len (length vector))
         (fitted-len (* +chunk-width+ (ceiling len +chunk-width+)))
         (data (locally (declare #+sbcl (muffle-conditions style-warning))
                 (make-array bit-depth :element-type 'succinct-bit-vector)))
         (zeros (make-array bit-depth :element-type '(integer 0 #.most-positive-fixnum)))
         (tmp (copy-seq vector))
         (lefts (make-array len :element-type (array-element-type vector)))
         (rights (make-array len :element-type (array-element-type vector)))
         (bits (make-array fitted-len :element-type 'bit)))
    (declare ((integer 0 #.most-positive-fixnum) len fitted-len)
             (vector tmp))
    (loop for d from (- bit-depth 1) downto 0
          do (let ((lpos 0)
                   (rpos 0))
               (declare ((integer 0 #.most-positive-fixnum) lpos rpos))
               (dotimes (i len)
                 (let ((bit (logand 1 (ash (aref tmp i) (- d)))))
                   (if (zerop bit)
                       (setf (aref lefts lpos) (aref tmp i)
                             lpos (+ lpos 1))
                       (setf (aref rights rpos) (aref tmp i)
                             rpos (+ rpos 1)))
                   (setf (aref bits i) bit)))
               (setf (aref data d) (make-sucbv! (copy-seq bits))
                     (aref zeros d) lpos)
               (rotatef lefts tmp)
               (replace tmp rights :start1 lpos :end2 rpos)))
    (%make-wavelet-matrix len data zeros)))

(define-condition invalid-wavelet-index-error (type-error)
  ((wavelet :initarg :wavelet :reader invalid-wavelet-index-error-wavelet)
   (index :initarg :index :reader invalid-wavelet-index-error-index))
  (:report
   (lambda (condition stream)
     (let ((index (invalid-wavelet-index-error-index condition)))
       (if (consp index)
           (format stream "Invalid range [~W, ~W) for wavelet-matrix ~W."
                   (car index)
                   (cdr index)
                   (invalid-wavelet-index-error-wavelet condition))
           (format stream "Invalid index ~W for wavelet-matrix ~W."
                   index
                   (invalid-wavelet-index-error-wavelet condition)))))))

(defun wavelet-range-count (wmatrix lo hi &key (start 0) end)
  (declare (optimize (speed 3))
           ((integer 0 #.most-positive-fixnum) lo hi start)
           ((or null (integer 0 #.most-positive-fixnum)) end))
  (let ((data (wavelet-data wmatrix))
        (zeros (wavelet-zeros wmatrix))
        (end (or end (wavelet-length wmatrix))))
    (assert (<= lo hi))
    (unless (<= start end (wavelet-length wmatrix))
      (error 'invalid-wavelet-index-error :index (cons start end) :wavelet wmatrix))
    (labels
        ((dfs (depth start end value)
           (declare ((integer 0 #.most-positive-fixnum) start end value)
                    ((integer -1 #.most-positive-fixnum) depth)
                    #+sbcl (values (integer 0 #.most-positive-fixnum)))
           (cond ((or (= start end)
                      (<= hi value))
                  0)
                 ((= depth -1)
                  (if (< value lo)
                      0
                      (- end start)))
                 (t
                  (let* ((next-value (logior value
                                             (the wavelet-integer (ash 1 depth))))
                         (upper-bound (logior next-value
                                              (- (the wavelet-integer (ash 1 depth)) 1))))
                    (cond ((< upper-bound lo)
                           0)
                          ((and (<= lo value) (< upper-bound hi))
                           (- end start))
                          (t
                           (let ((lcount (sucbv-rank (aref data depth) start))
                                 (rcount (sucbv-rank (aref data depth) end)))
                             (+ (dfs (- depth 1)
                                     (- start lcount)
                                     (- end rcount)
                                     value)
                                (dfs (- depth 1)
                                     (+ (aref zeros depth) lcount)
                                     (+ (aref zeros depth) rcount)
                                     next-value))))))))))
      (dfs (- (wavelet-depth wmatrix) 1) start end 0))))

(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
;;;

(defconstant +inf+ (- (expt 2 11) 1))

(defun main ()
  (let* ((n (read))
         (ws-plan (make-array (* 2 n) :element-type 'uint16 :initial-element +inf+))
         (bs-plan (make-array (* 2 n) :element-type 'uint16 :initial-element +inf+))
         (ws-pos (make-array (+ n 1) :element-type 'uint16))
         (bs-pos (make-array (+ n 1) :element-type 'uint16))
         (dp (make-array (list (+ n 1) (+ n 1))
                         :element-type 'uint32
                         :initial-element 0)))
    (declare (uint16 n))
    (dotimes (i (* 2 n))
      (let ((col (read))
            (a (read)))
        (if (eql col 'w)
            (setf (aref ws-plan i) a
                  (aref ws-pos a) i)
            (setf (aref bs-plan i) a
                  (aref bs-pos a) i))))
    (let ((ws-plan (make-wavelet 12 ws-plan))
          (bs-plan (make-wavelet 12 bs-plan)))
      (loop
        for x from 0 to n
        do (loop
             for y from 0 to n
             do (unless (= x y 0)
                  (setf (aref dp x y)
                        (min
                         (if (zerop y)
                             #xffffffff
                             (let ((pos (aref bs-pos y)))
                               (+ (aref dp x (- y 1))
                                  (wavelet-range-count ws-plan 0 (+ x 1) :start (+ pos 1))
                                  (wavelet-range-count bs-plan 0 y :start (+ pos 1))
                                  (wavelet-range-count ws-plan (+ x 1) 2001 :end pos)
                                  (wavelet-range-count bs-plan (+ y 1) 2001 :end pos))))
                         (if (zerop x)
                             #xffffffff
                             (let ((pos (aref ws-pos x)))
                               (+ (aref dp (- x 1) y)
                                  (wavelet-range-count ws-plan 0 x :start (+ pos 1))
                                  (wavelet-range-count bs-plan 0 (+ y 1) :start (+ pos 1))
                                  (wavelet-range-count ws-plan (+ x 1) 2001 :end pos)
                                  (wavelet-range-count bs-plan (+ y 1) 2001 :end pos))))))))))
    #>dp
    (println (floor (aref dp n n) 2))))

#-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:/Windows/System32/WindowsPowerShell/v1.0/powershell.exe" '("get-clipboard") :output out)
    (run-program "powershell.exe" '("-Command" "Get-Clipboard") :output out :search t)))

#+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 "3
B 1
W 2
B 3
W 1
W 3
B 2
"
    "4
"))
  (it.bese.fiveam:is
   (common-lisp-user::io-equal "4
B 4
W 4
B 3
W 3
B 2
W 2
B 1
W 1
"
    "18
"))
  (it.bese.fiveam:is
   (common-lisp-user::io-equal "9
W 3
B 1
B 4
W 1
B 5
W 9
W 2
B 6
W 5
B 3
W 8
B 9
W 7
B 2
B 8
W 4
W 6
B 7
"
    "41
")))