Submission #10331957


Source Code Expand

(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
(defmacro with-buffered-stdout (&body body)
  "Buffers all outputs to *STANDARD-OUTPUT* in BODY and flushes them to
*STANDARD-OUTPUT* after BODY has been done (without error). Note that only
BASE-CHAR is allowed."
  (let ((out (gensym)))
    `(let ((,out (make-string-output-stream :element-type 'base-char)))
       (let ((*standard-output* ,out))
         ,@body)
       (write-string (get-output-stream-string ,out)))))

(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 #\-))
                                  (setf 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))))))))

;;;
;;; Binary heap
;;;

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

(defmacro define-binary-heap (name &key (order '#'>) (element-type 'fixnum))
  "Defines a binary heap specialized for the given order and the element
type. This macro defines a structure of the name NAME and relevant functions:
MAKE-<NAME>, <NAME>-PUSH, <NAME>-POP, <NAME>-REINITIALIZE, <NAME>-EMPTY-P,
<NAME>-COUNT, and <NAME>-PEEK."
  (check-type name symbol)
  (let* ((string-name (string name))
         (fname-push (intern (format nil "~A-PUSH" string-name)))
         (fname-pop (intern (format nil "~A-POP" string-name)))
         (fname-reinitialize (intern (format nil "~A-REINITIALIZE" string-name)))
         (fname-empty-p (intern (format nil "~A-EMPTY-P" string-name)))
         (fname-count (intern (format nil "~A-COUNT" string-name)))
         (fname-peek (intern (format nil "~A-PEEK" string-name)))
         (fname-make (intern (format nil "MAKE-~A" string-name)))
         (acc-position (intern (format nil "~A-POSITION" string-name)))
         (acc-data (intern (format nil "~A-DATA" string-name))))
    `(progn
       (locally
           ;; prevent style warnings
           (declare #+sbcl (muffle-conditions style-warning))
         (defstruct (,name
                     (:constructor ,fname-make
                         (size
                          &aux (data ,(if (eql element-type '*)
                                          `(make-array (1+ size))
                                          `(make-array (1+ size) :element-type ',element-type))))))
           (data #() :type (simple-array ,element-type (*)))
           (position 1 :type (integer 1 #.most-positive-fixnum))))

       (declaim #+sbcl (sb-ext:maybe-inline ,fname-push))
       (defun ,fname-push (obj heap)
         "Adds OBJ to the end of HEAP."
         (declare (optimize (speed 3))
                  (type ,name heap))
         (symbol-macrolet ((position (,acc-position heap)))
           (when (>= position (length (,acc-data heap)))
             (setf (,acc-data heap)
                   (adjust-array (,acc-data heap)
                                 (min (- array-total-size-limit 1)
                                      (* position 2)))))
           (let ((data (,acc-data heap)))
             (declare ((simple-array ,element-type (*)) data))
             (labels ((update (pos)
                        (declare (optimize (speed 3) (safety 0)))
                        (unless (= pos 1)
                          (let ((parent-pos (ash pos -1)))
                            (when (funcall ,order (aref data pos) (aref data parent-pos))
                              (rotatef (aref data pos) (aref data parent-pos))
                              (update parent-pos))))))
               (setf (aref data position) obj)
               (update position)
               (incf position)
               heap))))

       (declaim #+sbcl (sb-ext:maybe-inline ,fname-pop))
       (defun ,fname-pop (heap)
         "Removes and returns the element at the top of HEAP."
         (declare (optimize (speed 3))
                  (type ,name heap))
         (symbol-macrolet ((position (,acc-position heap)))
           (let ((data (,acc-data heap)))
             (declare ((simple-array ,element-type (*)) data))
             (labels ((update (pos)
                        (declare (optimize (speed 3) (safety 0))
                                 ((integer 1 #.most-positive-fixnum) pos))
                        (let* ((child-pos1 (+ pos pos))
                               (child-pos2 (1+ child-pos1)))
                          (when (<= child-pos1 position)
                            (if (<= child-pos2 position)
                                (if (funcall ,order (aref data child-pos1) (aref data child-pos2))
                                    (unless (funcall ,order (aref data pos) (aref data child-pos1))
                                      (rotatef (aref data pos) (aref data child-pos1))
                                      (update child-pos1))
                                    (unless (funcall ,order (aref data pos) (aref data child-pos2))
                                      (rotatef (aref data pos) (aref data child-pos2))
                                      (update child-pos2)))
                                (unless (funcall ,order (aref data pos) (aref data child-pos1))
                                  (rotatef (aref data pos) (aref data child-pos1))))))))
               (when (= position 1)
                 (error 'heap-empty-error :heap heap))
               (prog1 (aref data 1)
                 (decf position)
                 (setf (aref data 1) (aref data position))
                 (update 1))))))

       (declaim (inline ,fname-reinitialize))
       (defun ,fname-reinitialize (heap)
         "Makes HEAP empty."
         (setf (,acc-position heap) 1)
         heap)

       (declaim (inline ,fname-empty-p))
       (defun ,fname-empty-p (heap)
         "Returns true iff HEAP is empty."
         (= 1 (,acc-position heap)))

       (declaim (inline ,fname-count))
       (defun ,fname-count (heap)
         "Returns the current number of the elements in HEAP."
         (- (,acc-position heap) 1))

       (declaim (inline ,fname-peek))
       (defun ,fname-peek (heap)
         "Returns the topmost element of HEAP."
         (if (= 1 (,acc-position heap))
             (error 'heap-empty-error :heap heap)
             (aref (,acc-data heap) 1))))))

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

;; day . duration
(define-binary-heap heap
  :order (lambda (node1 node2)
           (declare ((cons uint31 uint31) node1 node2))
           (< (+ (car node1) (cdr node1))
              (+ (car node2) (cdr node2))))
  :element-type (cons uint31 uint31))

(defstruct (t1queue (:constructor make-t1queue
                        (size &aux (heap (make-heap size)))))
  (sum 0 :type (integer 0 #.most-positive-fixnum))
  (heap nil :type heap))

(declaim (inline t1queue-push))
(defun t1queue-push (obj t1queue)
  (heap-push obj (t1queue-heap t1queue))
  t1queue)

(declaim (inline t1queue-pop))
(defun t1queue-pop (t1queue)
  (destructuring-bind (init-day . dur) (heap-pop (t1queue-heap t1queue))
    (declare (ignore init-day))
    (decf (t1queue-sum t1queue) dur)
    t1queue))

(declaim (inline t1queue-peek))
(defun t1queue-peek (t1queue)
  (heap-peek (t1queue-heap t1queue)))

(declaim (inline t1queue-step))
(defun t1queue-step (t1queue)
  (incf (t1queue-sum t1queue)
        (heap-count (t1queue-heap t1queue))))

(declaim (inline t1queue-empty-p))
(defun t1queue-empty-p (t1queue)
  (heap-empty-p (t1queue-heap t1queue)))

(defstruct (t2queue (:constructor make-t2queue
                        (size &aux (heap (make-heap size)))))
  (sum 0 :type (integer 0 #.most-positive-fixnum))
  (increment 0 :type fixnum)
  (heap nil :type heap))

(declaim (inline t2queue-push))
(defun t2queue-push (obj t2queue)
  (heap-push obj (t2queue-heap t2queue))
  (decf (t2queue-increment t2queue)) ;; -1からスタートして、stepで長さ*2を足す
  t2queue)

(declaim (inline t2queue-pop))
(defun t2queue-pop (t2queue)
  (destructuring-bind (init-day . dur) (heap-pop (t2queue-heap t2queue))
    (declare (ignore init-day))
    (decf (t2queue-increment t2queue) (- (* dur 2) 1))
    (decf (t2queue-sum t2queue) (* dur dur))
    t2queue))

(declaim (inline t2queue-peek))
(defun t2queue-peek (t2queue)
  (heap-peek (t2queue-heap t2queue)))

(declaim (inline t2queue-step))
(defun t2queue-step (t2queue)
  (incf (t2queue-increment t2queue)
        (* 2 (heap-count (t2queue-heap t2queue))))
  (incf (t2queue-sum t2queue)
        (t2queue-increment t2queue)))

(declaim (inline t2queue-empty-p))
(defun t2queue-empty-p (t2queue)
  (heap-empty-p (t2queue-heap t2queue)))

(defconstant +inf+ most-positive-fixnum)

(defun main ()
  (let* ((n (read))
         (q (read))
         (ws (make-array n :element-type 'uint62))
         (ts (make-array n :element-type 'uint8))
         (xs (make-array n :element-type 'uint31))
         (restored-day (make-array n :element-type 'int32 :initial-element -1))
         (res (make-array 3652426 :element-type 'uint62))
         (t0queue (make-heap n))
         (t1queue (make-t1queue n))
         (t2queue (make-t2queue n))
         (score 0))
    (dotimes (i n)
      (setf (aref ws i) (read-fixnum)
            (aref ts i) (read-fixnum)
            (aref xs i) (read-fixnum)))
    (let ((wpos 0))
      (dotimes (day (length res))
        ;; 今日のスコアを記録する
        (setf (aref res day) score)
        ;; 期限切れのサービスを消す
        (loop (when (heap-empty-p t0queue)
                (return))
              (destructuring-bind (init-day . dur) (heap-peek t0queue)
                (unless (= (+ init-day dur) day)
                  (return))
                (heap-pop t0queue)))
        (loop (when (t1queue-empty-p t1queue)
                (return))
              (destructuring-bind (init-day . dur) (t1queue-peek t1queue)
                (unless (= (+ init-day dur) day)
                  (return))
                (t1queue-pop t1queue)))
        (loop (when (t2queue-empty-p t2queue)
                (return))
              (destructuring-bind (init-day . dur) (t2queue-peek t2queue)
                (unless (= (+ init-day dur) day)
                  (return))
                (t2queue-pop t2queue)))
        ;; 今日復旧したサービスを加える
        (loop (when (= wpos n) (return))
              (let ((w (aref ws wpos))
                    (type (aref ts wpos))
                    (x (aref xs wpos)))
                (unless (>= score w)
                  (return))
                (setf (aref restored-day wpos) day)
                (ecase type
                  (0 (heap-push (cons day x) t0queue))
                  (1 (t1queue-push (cons day x) t1queue))
                  (2 (t2queue-push (cons day x) t2queue)))
                (incf wpos)))
        ;; 今日の分のスコアを更新する
        (incf score)
        (incf score (heap-count t0queue))
        (t1queue-step t1queue)
        (incf score (t1queue-sum t1queue))
        (t2queue-step t2queue)
        (incf score (t2queue-sum t2queue))))
    (with-buffered-stdout
      (sb-int:dovector (day restored-day)
        (if (= -1 day)
            (write-line "Many years later")
            (println day)))
      (dotimes (i q)
        (let ((y (read-fixnum)))
          (println (aref res y)))))))

#-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 "3 11
1 0 2
4 1 3
7 2 4
0
1
2
3
4
5
6
7
8
9
10
"
    "1
3
4
0
1
3
5
7
11
19
29
46
47
48
"))
  (it.bese.fiveam:is
   (common-lisp-user::io-equal "5 5
10000 0 20
10000 1 30
10000 0 40
10000 2 70
30000 2 10000
5000
10000
15000
20000
25000
"
    "10000
10000
10000
10000
10039
5000
10000
40711690801
329498273301
333383477320
"))
  (5am:is
   (io-equal "2 2
3652425 0 1
3652426 2 10000
3652424
3652425
"
             "3652425
Many years later
3652424
3652425
")))

Submission Info

Submission Time
Task F - Acceleration of Network
User sansaqua
Language Common Lisp (SBCL 1.1.14)
Score 100
Code Size 16578 Byte
Status AC
Exec Time 445 ms
Memory 79328 KiB

Judge Result

Set Name Partial 1 All
Score / Max Score 15 / 15 85 / 85
Status
AC × 24
AC × 60
Set Name Test Cases
Partial 1 0_00_sample_00, 0_10_Random_00_000000_000265, 0_10_Random_01_001000_000265, 0_10_Random_02_001000_000263, 0_10_Random_03_000003_000251, 0_10_Random_04_000003_000261, 0_10_Random_05_000003_000257, 0_10_Random_06_000009_000251, 0_10_Random_07_000000_000262, 0_10_Random_08_000000_000256, 0_10_Random_09_000003_000262, 0_10_Random_10_000002_000261, 0_10_Random_11_000006_000255, 0_10_Random_12_000004_000253, 0_10_Random_13_000054_000262, 0_10_Random_14_000033_000265, 0_10_Random_15_000052_000253, 0_10_Random_16_000000_000259, 0_10_Random_17_000078_000253, 0_10_Random_18_000417_000254, 0_10_Random_19_000417_000254, 0_10_Random_20_000913_000259, 0_10_Random_21_000238_000255, 0_10_Random_22_000335_000255
All 0_00_sample_00, 0_10_Random_00_000000_000265, 0_10_Random_01_001000_000265, 0_10_Random_02_001000_000263, 0_10_Random_03_000003_000251, 0_10_Random_04_000003_000261, 0_10_Random_05_000003_000257, 0_10_Random_06_000009_000251, 0_10_Random_07_000000_000262, 0_10_Random_08_000000_000256, 0_10_Random_09_000003_000262, 0_10_Random_10_000002_000261, 0_10_Random_11_000006_000255, 0_10_Random_12_000004_000253, 0_10_Random_13_000054_000262, 0_10_Random_14_000033_000265, 0_10_Random_15_000052_000253, 0_10_Random_16_000000_000259, 0_10_Random_17_000078_000253, 0_10_Random_18_000417_000254, 0_10_Random_19_000417_000254, 0_10_Random_20_000913_000259, 0_10_Random_21_000238_000255, 0_10_Random_22_000335_000255, 1_00_sample_01, 1_00_sample_02, 1_01_Teuchi_00, 1_01_Teuchi_01, 1_01_Teuchi_02, 1_01_Teuchi_03, 1_10_Random_23_086198_063414, 1_10_Random_24_041759_025278, 1_10_Random_25_078163_017646, 1_10_Random_26_082466_052832, 1_10_Random_27_069483_058001, 1_10_Random_28_037260_074459, 1_10_Random_29_094251_071690, 1_10_Random_30_080555_029493, 1_10_Random_31_099897_068369, 1_10_Random_32_086928_020563, 1_10_Random_33_019288_027448, 1_10_Random_34_027325_013687, 1_10_Random_35_037565_046230, 1_10_Random_36_053110_007707, 1_10_Random_37_006561_051152, 1_10_Random_38_001724_008865, 1_10_Random_39_075823_030498, 1_10_Random_40_035920_003446, 1_10_Random_41_061129_090693, 1_10_Random_42_026102_061986, 1_20_HalfRandom_00_033145_012808, 1_20_HalfRandom_01_051361_052902, 1_20_HalfRandom_02_072789_061928, 1_20_HalfRandom_03_080965_031006, 1_20_HalfRandom_04_039937_038308, 1_20_HalfRandom_05_098476_067390, 1_20_HalfRandom_06_061198_009066, 1_20_HalfRandom_07_096374_098697, 1_20_HalfRandom_08_077042_019386, 1_20_HalfRandom_09_023570_047790
Case Name Status Exec Time Memory
0_00_sample_00 AC 390 ms 79328 KiB
0_10_Random_00_000000_000265 AC 248 ms 68324 KiB
0_10_Random_01_001000_000265 AC 268 ms 72544 KiB
0_10_Random_02_001000_000263 AC 264 ms 72420 KiB
0_10_Random_03_000003_000251 AC 248 ms 68320 KiB
0_10_Random_04_000003_000261 AC 248 ms 68328 KiB
0_10_Random_05_000003_000257 AC 248 ms 68324 KiB
0_10_Random_06_000009_000251 AC 248 ms 68324 KiB
0_10_Random_07_000000_000262 AC 248 ms 68324 KiB
0_10_Random_08_000000_000256 AC 248 ms 68324 KiB
0_10_Random_09_000003_000262 AC 248 ms 68328 KiB
0_10_Random_10_000002_000261 AC 248 ms 68324 KiB
0_10_Random_11_000006_000255 AC 248 ms 68324 KiB
0_10_Random_12_000004_000253 AC 248 ms 68324 KiB
0_10_Random_13_000054_000262 AC 248 ms 68328 KiB
0_10_Random_14_000033_000265 AC 248 ms 68324 KiB
0_10_Random_15_000052_000253 AC 248 ms 68324 KiB
0_10_Random_16_000000_000259 AC 248 ms 68324 KiB
0_10_Random_17_000078_000253 AC 248 ms 68328 KiB
0_10_Random_18_000417_000254 AC 256 ms 72420 KiB
0_10_Random_19_000417_000254 AC 257 ms 72416 KiB
0_10_Random_20_000913_000259 AC 265 ms 72416 KiB
0_10_Random_21_000238_000255 AC 257 ms 72420 KiB
0_10_Random_22_000335_000255 AC 258 ms 72420 KiB
1_00_sample_01 AC 248 ms 68324 KiB
1_00_sample_02 AC 269 ms 68324 KiB
1_01_Teuchi_00 AC 362 ms 75236 KiB
1_01_Teuchi_01 AC 316 ms 74596 KiB
1_01_Teuchi_02 AC 248 ms 68324 KiB
1_01_Teuchi_03 AC 337 ms 74596 KiB
1_10_Random_23_086198_063414 AC 395 ms 75616 KiB
1_10_Random_24_041759_025278 AC 345 ms 72936 KiB
1_10_Random_25_078163_017646 AC 334 ms 74980 KiB
1_10_Random_26_082466_052832 AC 383 ms 75488 KiB
1_10_Random_27_069483_058001 AC 372 ms 75488 KiB
1_10_Random_28_037260_074459 AC 364 ms 73696 KiB
1_10_Random_29_094251_071690 AC 401 ms 75748 KiB
1_10_Random_30_080555_029493 AC 354 ms 75108 KiB
1_10_Random_31_099897_068369 AC 414 ms 75876 KiB
1_10_Random_32_086928_020563 AC 349 ms 74980 KiB
1_10_Random_33_019288_027448 AC 303 ms 72932 KiB
1_10_Random_34_027325_013687 AC 294 ms 72804 KiB
1_10_Random_35_037565_046230 AC 336 ms 73316 KiB
1_10_Random_36_053110_007707 AC 316 ms 72804 KiB
1_10_Random_37_006561_051152 AC 312 ms 73188 KiB
1_10_Random_38_001724_008865 AC 267 ms 72544 KiB
1_10_Random_39_075823_030498 AC 362 ms 75368 KiB
1_10_Random_40_035920_003446 AC 295 ms 72676 KiB
1_10_Random_41_061129_090693 AC 407 ms 76132 KiB
1_10_Random_42_026102_061986 AC 344 ms 73444 KiB
1_20_HalfRandom_00_033145_012808 AC 321 ms 72808 KiB
1_20_HalfRandom_01_051361_052902 AC 358 ms 73448 KiB
1_20_HalfRandom_02_072789_061928 AC 394 ms 75748 KiB
1_20_HalfRandom_03_080965_031006 AC 365 ms 75620 KiB
1_20_HalfRandom_04_039937_038308 AC 343 ms 73316 KiB
1_20_HalfRandom_05_098476_067390 AC 410 ms 76260 KiB
1_20_HalfRandom_06_061198_009066 AC 329 ms 75108 KiB
1_20_HalfRandom_07_096374_098697 AC 445 ms 76768 KiB
1_20_HalfRandom_08_077042_019386 AC 350 ms 75492 KiB
1_20_HalfRandom_09_023570_047790 AC 341 ms 73316 KiB