(in-package :cl-user)
(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)) `(values ,(read s nil nil t)))))
#+swank (cl-syntax:use-syntax cl-debug-print:debug-print-syntax)

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

(defconstant +mod+ 1000000007)

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

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

;; BEGIN_INSERTED_CONTENTS
(defpackage :cp/map-indices
  (:use :cl)
  (:export #:map-indices #:do-indices))
(in-package :cp/map-indices)

(declaim (inline map-indices))
(defun map-indices (function max-indices)
  "Applies function to each vector of indices smaller than MAX-INDICES. The
consequence is undefined when the vector is modified in FUNCTION."
  (declare (vector max-indices))
  (let* ((size (length max-indices))
         (indices (make-array size :element-type (array-element-type max-indices))))
    (labels ((recur (pos)
               (declare ((integer 0 #.array-dimension-limit) pos))
               (if (= pos size)
                   (funcall function indices)
                   (dotimes (idx (the (integer 0 #.most-positive-fixnum)
                                      (aref max-indices pos)))
                     (setf (aref indices pos) idx)
                     (recur (+ pos 1))))))
      (recur 0))))

(defmacro do-indices ((var end-indices) &body body)
  "DO-style macro for MAP-INDICES"
  `(block nil (map-indices (lambda (,var) ,@body) ,end-indices)))

(defpackage :cp/modify-macro
  (:use :cl)
  (:export #:minf #:maxf #:mulf #:divf #:iorf #:xorf #:andf))
(in-package :cp/modify-macro)

(macrolet ((def (name fname)
             `(define-modify-macro ,name (new-value) ,fname)))
  (def minf min)
  (def maxf max)
  (def mulf *)
  (def divf /)
  (def iorf logior)
  (def xorf logxor)
  (def andf logand))

;; BEGIN_USE_PACKAGE
(eval-when (:compile-toplevel :load-toplevel :execute)
  (use-package :cp/modify-macro :cl-user))
(eval-when (:compile-toplevel :load-toplevel :execute)
  (use-package :cp/map-indices :cl-user))
(in-package :cl-user)

;;;
;;; Body
;;;

(defun main ()
  (let* ((n (read))
         (a (read))
         (b (read))
         (c (read))
         (ls (coerce (loop repeat n collect (read)) '(simple-array uint31 (*))))
         (univ (coerce (loop repeat n collect 4) '(simple-array uint8 (*))))
         (res most-positive-fixnum))
    (do-indices (indices univ)
      (let ((asum 0)
            (bsum 0)
            (csum 0)
            (cost 0))
        (dotimes (i n)
          (ecase (aref indices i)
            (0)
            (1 (incf cost 10)
             (incf asum (aref ls i)))
            (2 (incf cost 10)
             (incf bsum (aref ls i)))
            (3 (incf cost 10)
             (incf csum (aref ls i))))
          (unless (or (zerop asum) (zerop bsum) (zerop csum))
            (minf res
                  (+ cost -30
                     (abs (- asum a)) (abs (- bsum b)) (abs (- csum c))))))))
    (println res)))

#-swank (main)

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

#+swank
(defun get-clipbrd ()
  (with-output-to-string (out)
    #+os-windows (run-program "powershell.exe" '("-Command" "Get-Clipboard") :output out :search t)
    #+os-unix (run-program "xsel" '("-b" "-o") :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* (or out (make-string-output-stream)))
         (res (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))))))
    (if out res (get-output-stream-string *standard-output*))))

#+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)))

#-swank
(eval-when (:compile-toplevel)
  (when (and (boundp 'sb-c::*compiler-warning-count*)
             (> sb-c::*compiler-warning-count* 0))
    (sb-ext:quit :unix-status 1)))

;; To run: (5am:run! :sample)
#+swank
(it.bese.fiveam:test :sample
  (it.bese.fiveam:is
   (equal "23
"
          (run "5 100 90 80
98
40
30
21
80
" nil)))
  (it.bese.fiveam:is
   (equal "0
"
          (run "8 100 90 80
100
100
90
90
90
80
80
80
" nil)))
  (it.bese.fiveam:is
   (equal "243
"
          (run "8 1000 800 100
300
333
400
444
500
555
600
666
" nil))))


Measured memory_bytes: 24928