Submission #13574857


Source Code Expand

#-swank
(unless (member :child-sbcl *features*)
  (quit
   :unix-status
   (process-exit-code
    (run-program *runtime-pathname*
                 `("--control-stack-size" "128MB"
                   "--noinform" "--disable-ldb" "--lose-on-corruption" "--end-runtime-options"
                   "--eval" "(push :child-sbcl *features*)"
                   "--script" ,(namestring *load-pathname*))
                 :output t :error t :input t))))
(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)
#-swank (disable-debugger) ; for CS Academy

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

;;;
;;; Memoization macro
;;;

;;
;; Basic usage:
;;
;; (with-cache (:hash-table :test #'equal :key #'cons)
;;   (defun add (a b)
;;     (+ a b)))
;; This function caches the returned values for already passed combinations of
;; arguments. In this case ADD stores the key (CONS A B) and the returned value
;; to a hash-table when (ADD A B) is evaluated for the first time. ADD returns
;; the stored value when it is called with the same arguments (w.r.t. EQUAL)
;; again.
;;
;; The storage for cache can be hash-table or array. Let's see an example for
;; array:
;; (with-cache (:array (10 20 30) :initial-element -1 :element-type 'fixnum)
;;   (defun foo (a b c) ... ))
;; This form stores the value of FOO in an array created by (make-array (list 10
;; 20 30) :initial-element -1 :element-type 'fixnum). Note that INITIAL-ELEMENT
;; must always be given here as it is used as the flag expressing `not yet
;; stored'. (Therefore INITIAL-ELEMENT should be a value FOO never takes.)
;;
;; If you want to ignore some arguments, you can put `*' in dimensions:
;; (with-cache (:array (10 10 * 10) :initial-element -1)
;;   (defun foo (a b c d) ...)) ; then C is ignored when querying or storing cache
;;
;; Available definition forms in WITH-CACHE are DEFUN, LABELS, FLET, and
;; SB-INT:NAMED-LET.
;;
;; You can trace the memoized function by :TRACE option:
;; (with-cache (:array (10 10) :initial-element -1 :trace t)
;;   (defun foo (x y) ...))
;; Then FOO is traced as with CL:TRACE.
;;

;; TODO & NOTE: Currently a memoized function is not enclosed with a block of
;; the function name.

;; FIXME: *RECURSION-DEPTH* should be included within the macro.
(declaim (type (integer 0 #.most-positive-fixnum) *recursion-depth*))
(defparameter *recursion-depth* 0)

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defun %enclose-with-trace (fname args form)
    (let ((value (gensym)))
      `(progn
         (format t "~&~A~A: (~A ~{~A~^ ~}) =>"
                 (make-string *recursion-depth*
                              :element-type 'base-char
                              :initial-element #\ )
                 *recursion-depth*
                 ',fname
                 (list ,@args))
         (let ((,value (let ((*recursion-depth* (1+ *recursion-depth*)))
                         ,form)))
           (format t "~&~A~A: (~A ~{~A~^ ~}) => ~A"
                   (make-string *recursion-depth*
                                :element-type 'base-char
                                :initial-element #\ )
                   *recursion-depth*
                   ',fname
                   (list ,@args)
                   ,value)
           ,value))))

  (defun %extract-declarations (body)
    (remove-if-not (lambda (form) (and (consp form) (eql 'declare (car form))))
                   body))

  (defun %parse-cache-form (cache-specifier)
    (let ((cache-type (car cache-specifier))
          (cache-attribs (cdr cache-specifier)))
      (assert (member cache-type '(:hash-table :array)))
      (let* ((dims-with-* (when (eql cache-type :array) (first cache-attribs)))
             (dims (remove '* dims-with-*))
             (rank (length dims))
             (rest-attribs (ecase cache-type
                             (:hash-table cache-attribs)
                             (:array (cdr cache-attribs))))
             (key (prog1 (getf rest-attribs :key) (remf rest-attribs :key)))
             (trace-p (prog1 (getf rest-attribs :trace) (remf rest-attribs :trace)))
             (cache-form (case cache-type
                           (:hash-table `(make-hash-table ,@rest-attribs))
                           (:array `(make-array (list ,@dims) ,@rest-attribs))))
             (initial-element (when (eql cache-type :array)
                                (assert (member :initial-element rest-attribs))
                                (getf rest-attribs :initial-element))))
        (let ((cache (gensym "CACHE"))
              (value (gensym))
	      (present-p (gensym))
              (name-alias (gensym))
	      (args-lst (gensym))
              (indices (loop repeat rank collect (gensym))))
          (labels
              ((make-cache-querier (cache-type name args)
                 (let ((res (case cache-type
                              (:hash-table
                               `(let ((,args-lst (funcall ,(or key '#'list) ,@args)))
                                  (multiple-value-bind (,value ,present-p)
                                      (gethash ,args-lst ,cache)
                                    (if ,present-p
                                        ,value
                                        (setf (gethash ,args-lst ,cache)
                                              (,name-alias ,@args))))))
                              (:array
                               (assert (= (length args) (length dims-with-*)))
                               (let ((memoized-args (loop for dimension in dims-with-*
                                                          for arg in args
                                                          unless (eql dimension '*)
                                                          collect arg)))
                                 (if key
                                     `(multiple-value-bind ,indices
                                          (funcall ,key ,@memoized-args)
                                        (let ((,value (aref ,cache ,@indices)))
                                          (if (eql ,initial-element ,value)
                                              (setf (aref ,cache ,@indices)
                                                    (,name-alias ,@args))
                                              ,value)))
                                     `(let ((,value (aref ,cache ,@memoized-args)))
                                        (if (eql ,initial-element ,value)
                                            (setf (aref ,cache ,@memoized-args)
                                                  (,name-alias ,@args))
                                            ,value))))))))
                   (if trace-p
                       (%enclose-with-trace name args res)
                       res)))
               (make-reset-form (cache-type)
                 (case cache-type
                   (:hash-table `(setf ,cache (make-hash-table ,@rest-attribs)))
                   (:array `(prog1 nil
                              ;; TODO: portable fill
                              (fill (array-storage-vector ,cache) ,initial-element)))))
               (make-reset-name (name)
                 (intern (format nil "RESET-~A" (symbol-name name)))))
            (values cache cache-form cache-type name-alias
                    #'make-reset-name
                    #'make-reset-form
                    #'make-cache-querier)))))))

(defmacro with-cache ((cache-type &rest cache-attribs) def-form)
  "CACHE-TYPE := :HASH-TABLE | :ARRAY.
DEF-FORM := definition form with DEFUN, LABELS, FLET, or SB-INT:NAMED-LET."
  (multiple-value-bind (cache-symbol cache-form cache-type name-alias
                        make-reset-name make-reset-form
                        make-cache-querier)
      (%parse-cache-form (cons cache-type cache-attribs))
    (ecase (car def-form)
      ((defun)
       (destructuring-bind (_ name args &body body) def-form
         (declare (ignore _))
         `(let ((,cache-symbol ,cache-form))
            (defun ,(funcall make-reset-name name) ()
              ,(funcall make-reset-form cache-type))
            (defun ,name ,args
              ,@(%extract-declarations body)
              (labels ((,name-alias ,args ,@body))
                (declare (inline ,name-alias))
                ,(funcall make-cache-querier cache-type name args))))))
      ((labels flet)
       (destructuring-bind (_ definitions &body labels-body) def-form
         (declare (ignore _))
         (destructuring-bind (name args &body body) (car definitions)
           `(let ((,cache-symbol ,cache-form))
              (,(car def-form)
               ((,(funcall make-reset-name name) ()
                 ,(funcall make-reset-form cache-type))
                (,name ,args
                       ,@(%extract-declarations body)
                       (labels ((,name-alias ,args ,@body))
                         (declare (inline ,name-alias))
                         ,(funcall make-cache-querier cache-type name args)))
                ,@(cdr definitions))
               (declare (ignorable #',(funcall make-reset-name name)))
               ,@labels-body)))))
      ((nlet #+sbcl sb-int:named-let)
       (destructuring-bind (_ name bindings &body body) def-form
         (declare (ignore _))
         `(let ((,cache-symbol ,cache-form))
            (,(car def-form) ,name ,bindings
             ,@(%extract-declarations body)
             ,(let ((args (mapcar (lambda (x) (if (atom x) x (car x))) bindings)))
                `(labels ((,name-alias ,args ,@body))
                   (declare (inline ,name-alias))
                   ,(funcall make-cache-querier cache-type name args))))))))))

(declaim (inline bisect-right))
(defun bisect-right (target value &key (start 0) end (order #'<) (key #'identity))
  "TARGET := vector | function (taking an integer argument)
ORDER := strict order

Analogue of upper_bound() of C++ or bisect_right() of Python: Returns the
smallest index (or input) i that fulfills TARGET[i] > VALUE. In other words,
this function returns the rightmost index at which VALUE can be inserted with
keeping the order. Therefore, TARGET must be monotonically non-decreasing with
respect to ORDER.

- This function returns END if VALUE >= TARGET[END-1].
- The range [START, END) is half-open.
- END must be explicitly specified if TARGET is function.
- KEY is applied to each element of TARGET before comparison."
  (declare (function key order)
           (integer start)
           ((or null integer) end))
  (macrolet
      ((frob (accessor &optional declaration)
         `(labels
              ((%bisect-right (ng ok)
                 ;; TARGET[OK] > VALUE always holds (assuming
                 ;; TARGET[END] = +infinity)
                 ,@(when declaration (list declaration))
                 (if (<= (- ok ng) 1)
                     ok
                     (let ((mid (ash (+ ng ok) -1)))
                       (if (funcall order value (funcall key (,accessor target mid)))
                           (%bisect-right ng mid)
                           (%bisect-right mid ok))))))
            (assert (<= start end))
            (%bisect-right (- start 1) end))))
    (etypecase target
      (vector
       (let ((end (or end (length target))))
         (frob aref (declare ((integer -1 (#.array-total-size-limit)) ng ok)))))
      (function
       (assert end () "Requires END argument if TARGET is a function.")
       (frob funcall)))))

(declaim (ftype (function * (values fixnum &optional)) read-fixnum))
(defun read-fixnum (&optional (in *standard-input*))
  "NOTE: cannot read -2^62"
  (declare #.OPT)
  (macrolet ((%read-byte ()
               `(the (unsigned-byte 8)
                     #+swank (char-code (read-char in nil #\Nul))
                     #-swank (sb-impl::ansi-stream-read-byte in nil #.(char-code #\Nul) nil))))
    (let* ((minus nil)
           (result (loop (let ((byte (%read-byte)))
                           (cond ((<= 48 byte 57)
                                  (return (- byte 48)))
                                 ((zerop byte) ; #\Nul
                                  (error "Read EOF or #\Nul."))
                                 ((= byte #.(char-code #\-))
                                  (setq minus t)))))))
      (declare ((integer 0 #.most-positive-fixnum) result))
      (loop
        (let* ((byte (%read-byte)))
          (if (<= 48 byte 57)
              (setq result (+ (- byte 48)
                              (* 10 (the (integer 0 #.(floor most-positive-fixnum 10))
                                         result))))
              (return (if minus (- result) result))))))))

(in-package :cl-user)

(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 solve-small (a b x)
  (aref #(0 2 1 2 2 1 2 1 2 2 1) x))

(defconstant +inf+ most-positive-fixnum)

(defun solve (a b x)
  (declare #.OPT)
  (let ((seq (make-array 90 :element-type 'uint62 :initial-element 0))
        (dp (make-array '(91 2) :element-type 'uint62 :initial-element 0))
        (maxs (make-array 90 :element-type 'uint62 :initial-element 0)))
    (declare ((simple-array uint62 (*)) seq maxs))
    (setf (aref seq 0) a
          (aref seq 1) b)
    (loop for i from 2 below (length seq)
          do (setf (aref seq i)
                   (min +inf+ (+ (aref seq (- i 1)) (aref seq (- i 2))))))
    (dotimes (x (length seq))
      (maxf (aref dp (+ x 1) 1)
            (min +inf+ (+ (aref dp x 0) (aref seq x))))
      (maxf (aref dp (+ x 1) 0)
            (min +inf+ (max (aref dp x 0) (aref dp x 1)))))
    (dotimes (x (length maxs))
      (setf (aref maxs x)
            (max (aref dp (+ x 1) 1) (aref dp (+ x 1) 0))))
    ;; #>seq
    ;; #>cumuls
    (let ((std-pos (- (bisect-right seq x) 1)))
      (with-cache (:hash-table :test #'equal)
        (labels ((dp (pos sum)
                   (declare (int32 pos)
                            (uint62 sum)
                            (values uint62 &optional))
                   (cond ((zerop sum) 1)
                         ((< pos 0) 0)
                         ((< (aref maxs pos) sum) 0)
                         ((< sum (aref seq pos))
                          (dp (- pos 1) sum))
                         (t
                          (+ (dp (- pos 1) sum)
                             (dp (- pos 2) (- sum (aref seq pos))))))))
          (dp std-pos x))))))

(defun main ()
  (let* ((q (read)))
    (write-string
     (with-output-to-string (*standard-output* nil :element-type 'base-char)
       (dotimes (_ q)
         (let ((a (read-fixnum))
               (b (read-fixnum))
               (x (read-fixnum)))
           (println
            (cond ;; ((and (= a b 1) (<= x 10))
              ;;  (solve-small a b x))
              (t (solve a b x))))))))))

#-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 "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 "2
1 1 1
1 1 9
"
    "2
2
"))
  (it.bese.fiveam:is
   (common-lisp-user::io-equal "3
1 2 32
5 2 1
2 1 70
"
    "1
0
2
")))

Submission Info

Submission Time
Task E - 美しい和音
User sansaqua
Language Common Lisp (SBCL 1.1.14)
Score 100
Code Size 18731 Byte
Status AC
Exec Time 1164 ms
Memory 66872 KiB

Judge Result

Set Name Sample Subtask1 Subtask2 Subtask3
Score / Max Score 0 / 0 11 / 11 31 / 31 58 / 58
Status
AC × 2
AC × 11
AC × 42
AC × 62
Set Name Test Cases
Sample sample_01.txt, sample_02.txt
Subtask1 sample_01.txt, sub1_01.txt, sub1_02.txt, sub1_03.txt, sub1_04.txt, sub1_05.txt, sub1_06.txt, sub1_07.txt, sub1_08.txt, sub1_09.txt, sub1_10.txt
Subtask2 sample_01.txt, sample_02.txt, sub1_01.txt, sub1_02.txt, sub1_03.txt, sub1_04.txt, sub1_05.txt, sub1_06.txt, sub1_07.txt, sub1_08.txt, sub1_09.txt, sub1_10.txt, sub2_01.txt, sub2_02.txt, sub2_03.txt, sub2_04.txt, sub2_05.txt, sub2_06.txt, sub2_07.txt, sub2_08.txt, sub2_09.txt, sub2_10.txt, sub2_11.txt, sub2_12.txt, sub2_13.txt, sub2_14.txt, sub2_15.txt, sub2_16.txt, sub2_17.txt, sub2_18.txt, sub2_19.txt, sub2_20.txt, sub2_21.txt, sub2_22.txt, sub2_23.txt, sub2_24.txt, sub2_25.txt, sub2_26.txt, sub2_27.txt, sub2_28.txt, sub2_29.txt, sub2_30.txt
Subtask3 sample_01.txt, sample_02.txt, sub1_01.txt, sub1_02.txt, sub1_03.txt, sub1_04.txt, sub1_05.txt, sub1_06.txt, sub1_07.txt, sub1_08.txt, sub1_09.txt, sub1_10.txt, sub2_01.txt, sub2_02.txt, sub2_03.txt, sub2_04.txt, sub2_05.txt, sub2_06.txt, sub2_07.txt, sub2_08.txt, sub2_09.txt, sub2_10.txt, sub2_11.txt, sub2_12.txt, sub2_13.txt, sub2_14.txt, sub2_15.txt, sub2_16.txt, sub2_17.txt, sub2_18.txt, sub2_19.txt, sub2_20.txt, sub2_21.txt, sub2_22.txt, sub2_23.txt, sub2_24.txt, sub2_25.txt, sub2_26.txt, sub2_27.txt, sub2_28.txt, sub2_29.txt, sub2_30.txt, sub3_01.txt, sub3_02.txt, sub3_03.txt, sub3_04.txt, sub3_05.txt, sub3_06.txt, sub3_07.txt, sub3_08.txt, sub3_09.txt, sub3_10.txt, sub3_11.txt, sub3_12.txt, sub3_13.txt, sub3_14.txt, sub3_15.txt, sub3_16.txt, sub3_17.txt, sub3_18.txt, sub3_19.txt, sub3_20.txt
Case Name Status Exec Time Memory
sample_01.txt AC 173 ms 35128 KiB
sample_02.txt AC 154 ms 33976 KiB
sub1_01.txt AC 154 ms 33980 KiB
sub1_02.txt AC 158 ms 33976 KiB
sub1_03.txt AC 154 ms 33972 KiB
sub1_04.txt AC 155 ms 33972 KiB
sub1_05.txt AC 155 ms 33976 KiB
sub1_06.txt AC 156 ms 33972 KiB
sub1_07.txt AC 158 ms 33976 KiB
sub1_08.txt AC 155 ms 33976 KiB
sub1_09.txt AC 155 ms 33972 KiB
sub1_10.txt AC 157 ms 33980 KiB
sub2_01.txt AC 157 ms 33976 KiB
sub2_02.txt AC 158 ms 33976 KiB
sub2_03.txt AC 155 ms 33976 KiB
sub2_04.txt AC 160 ms 33976 KiB
sub2_05.txt AC 157 ms 33976 KiB
sub2_06.txt AC 156 ms 33976 KiB
sub2_07.txt AC 158 ms 33976 KiB
sub2_08.txt AC 158 ms 33980 KiB
sub2_09.txt AC 157 ms 33980 KiB
sub2_10.txt AC 156 ms 33976 KiB
sub2_11.txt AC 156 ms 33980 KiB
sub2_12.txt AC 157 ms 33972 KiB
sub2_13.txt AC 159 ms 33976 KiB
sub2_14.txt AC 159 ms 33976 KiB
sub2_15.txt AC 158 ms 33976 KiB
sub2_16.txt AC 158 ms 33980 KiB
sub2_17.txt AC 157 ms 33972 KiB
sub2_18.txt AC 158 ms 33976 KiB
sub2_19.txt AC 157 ms 33972 KiB
sub2_20.txt AC 155 ms 33972 KiB
sub2_21.txt AC 157 ms 33976 KiB
sub2_22.txt AC 156 ms 33976 KiB
sub2_23.txt AC 167 ms 33976 KiB
sub2_24.txt AC 157 ms 33976 KiB
sub2_25.txt AC 156 ms 33976 KiB
sub2_26.txt AC 157 ms 33980 KiB
sub2_27.txt AC 157 ms 33972 KiB
sub2_28.txt AC 155 ms 33976 KiB
sub2_29.txt AC 155 ms 33976 KiB
sub2_30.txt AC 156 ms 33972 KiB
sub3_01.txt AC 1164 ms 64756 KiB
sub3_02.txt AC 1139 ms 64820 KiB
sub3_03.txt AC 1141 ms 64852 KiB
sub3_04.txt AC 1139 ms 64852 KiB
sub3_05.txt AC 1135 ms 64760 KiB
sub3_06.txt AC 1137 ms 64820 KiB
sub3_07.txt AC 1141 ms 64860 KiB
sub3_08.txt AC 1137 ms 64852 KiB
sub3_09.txt AC 1140 ms 64828 KiB
sub3_10.txt AC 1137 ms 66872 KiB
sub3_11.txt AC 1142 ms 64856 KiB
sub3_12.txt AC 1139 ms 64856 KiB
sub3_13.txt AC 1137 ms 64888 KiB
sub3_14.txt AC 1129 ms 64824 KiB
sub3_15.txt AC 1132 ms 64856 KiB
sub3_16.txt AC 855 ms 64820 KiB
sub3_17.txt AC 977 ms 64852 KiB
sub3_18.txt AC 993 ms 64852 KiB
sub3_19.txt AC 993 ms 64728 KiB
sub3_20.txt AC 993 ms 64788 KiB