Submission #10380000


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
(declaim (ftype (function * (values fixnum &optional)) read-fixnum))
(defun read-fixnum (&optional (in *standard-input*))
  "NOTE: cannot read -2^62"
  (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))))))))

;;;
;;; 1-dimensional binary indexed tree on arbitrary commutative monoid
;;;

(defmacro define-bitree (name &key (operator '#'+) (identity 0) sum-type (order '#'<))
  "OPERATOR := binary operator (comprising a commutative monoid)
IDENTITY := object (identity element of the monoid)
ORDER := nil | strict comparison operator on the monoid
SUM-TYPE := nil | type specifier

Defines no structure; BIT is just a vector. This macro defines the three
functions: <NAME>-UPDATE!, point-update function, <NAME>-SUM, query function for
prefix sum, and COERCE-TO-<NAME>!, constructor. If ORDER is specified, this
macro in addition defines <NAME>-BISECT-LEFT and <NAME>-BISECT-RIGHT, the
bisection functions for prefix sums. (Note that these functions work only when
the sequence of prefix sums (VECTOR[0], VECTOR[0]+VECTOR[1], ...) is monotone.)

SUM-TYPE is used only for the type declaration: each sum
VECTOR[i]+VECTOR[i+1]...+VECTOR[i+k] is declared to be this type. (The
element-type of vector itself doesn't need to be SUM-TYPE.)"
  (let* ((name (string name))
         (fname-update (intern (format nil "~A-UPDATE!" name)))
         (fname-sum (intern (format nil "~A-SUM" name)))
         (fname-coerce (intern (format nil "COERCE-TO-~A!" name)))
         (fname-bisect-left (intern (format nil "~A-BISECT-LEFT" name)))
         (fname-bisect-right (intern (format nil "~A-BISECT-RIGHT" name))))
    `(progn
       (declaim (inline ,fname-update))
       (defun ,fname-update (bitree index delta)
         "Destructively increments the vector: vector[INDEX] = vector[INDEX] +
DELTA"
         (let ((len (length bitree)))
           (do ((i index (logior i (+ i 1))))
               ((>= i len) bitree)
             (declare ((integer 0 #.most-positive-fixnum) i))
             (setf (aref bitree i)
                   (funcall ,operator (aref bitree i) delta)))))

       (declaim (inline ,fname-sum))
       (defun ,fname-sum (bitree end)
         "Returns the sum of the prefix: vector[0] + ... + vector[END-1]."
         (declare ((integer 0 #.most-positive-fixnum) end))
         (let ((res ,identity))
           ,@(when sum-type `((declare (type ,sum-type res))))
           (do ((i (- end 1) (- (logand i (+ i 1)) 1)))
               ((< i 0) res)
             (declare ((integer -1 #.most-positive-fixnum) i))
             (setf res (funcall ,operator res (aref bitree i))))))

       (declaim (inline ,fname-coerce))
       (defun ,fname-coerce (vector)
         "Destructively constructs BIT from VECTOR. (You will not need to call
this constructor if what you need is a `zero-filled' BIT, because a vector
filled with the identity elements is a valid BIT as it is.)"
         (loop with len = (length vector)
               for i below len
               for dest-i = (logior i (+ i 1))
               when (< dest-i len)
               do (setf (aref vector dest-i)
                        (funcall ,operator (aref vector dest-i) (aref vector i)))
               finally (return vector)))

       ,@(when order
           `((declaim (inline ,fname-bisect-left))
             (defun ,fname-bisect-left (bitree value)
               "Returns the smallest index that satisfies VECTOR[0]+ ... +
VECTOR[index] >= VALUE. Returns the length of VECTOR if VECTOR[0]+
... +VECTOR[length-1] < VALUE. Note that this function deals with a **closed**
interval."
               (declare (vector bitree))
               (if (not (funcall ,order ,identity value))
                   0
                   (let ((len (length bitree))
                         (index+1 0)
                         (cumul ,identity))
                     (declare ((integer 0 #.most-positive-fixnum) index+1)
                              ,@(when sum-type
                                  `((type ,sum-type cumul))))
                     (do ((delta (ash 1 (- (integer-length len) 1))
                                 (ash delta -1)))
                         ((zerop delta) index+1)
                       (declare ((integer 0 #.most-positive-fixnum) delta))
                       (let ((next-index (+ index+1 delta -1)))
                         (when (< next-index len)
                           (let ((next-cumul (funcall ,operator cumul (aref bitree next-index))))
                             ,@(when sum-type
                                 `((declare (type ,sum-type next-cumul))))
                             (when (funcall ,order next-cumul value)
                               (setf cumul next-cumul)
                               (incf index+1 delta)))))))))
             (declaim (inline ,fname-bisect-right))
             (defun ,fname-bisect-right (bitree value)
               "Returns the smallest index that satisfies VECTOR[0]+ ... +
VECTOR[index] > VALUE. Returns the length of VECTOR if VECTOR[0]+
... +VECTOR[length-1] <= VALUE. Note that this function deals with a **closed**
interval."
               (declare (vector bitree))
               (if (funcall ,order value ,identity)
                   0
                   (let ((len (length bitree))
                         (index+1 0)
                         (cumul ,identity))
                     (declare ((integer 0 #.most-positive-fixnum) index+1)
                              ,@(when sum-type
                                  `((type ,sum-type cumul))))
                     (do ((delta (ash 1 (- (integer-length len) 1))
                                 (ash delta -1)))
                         ((zerop delta) index+1)
                       (declare ((integer 0 #.most-positive-fixnum) delta))
                       (let ((next-index (+ index+1 delta -1)))
                         (when (< next-index len)
                           (let ((next-cumul (funcall ,operator cumul (aref bitree next-index))))
                             ,@(when sum-type
                                 `((declare (type ,sum-type next-cumul))))
                             (unless (funcall ,order value next-cumul)
                               (setf cumul next-cumul)
                               (incf index+1 delta))))))))))))))

(define-bitree bitree
  :operator #'+
  :identity 0
  :sum-type fixnum
  :order #'<)

;; Example: compute the number of inversions in a sequence
#|
(declaim (inline make-inverse-lookup-table))
(defun make-inverse-lookup-table (vector &key (test #'eql))
  "Assigns each value of the (usually sorted) VECTOR of length n to the integers
0, ..., n-1."
  (let ((table (make-hash-table :test test :size (length vector))))
    (dotimes (i (length vector) table)
      (setf (gethash (aref vector i) table) i))))

(defun calc-inversion-number (vector &key (order #'<))
  (declare (vector vector))
  (let* ((len (length vector))
         (inv-lookup-table (make-inverse-lookup-table (sort (copy-seq vector) order)))
         (bitree (make-array len :element-type '(integer 0 #.most-positive-fixnum)))
         (inversion-number 0))
    (declare (integer inversion-number))
    (loop for j below len
          for element = (aref vector j)
          for compressed = (gethash element inv-lookup-table)
          for delta of-type integer = (- j (bitree-sum bitree (1+ compressed)))
          do (incf inversion-number delta)
             (bitree-update! bitree compressed 1))
    inversion-number))

(progn
  (assert (= 3 (calc-inversion-number #(2 4 1 3 5))))
  (assert (zerop (calc-inversion-number #(0))))
  (assert (zerop (calc-inversion-number #())))
  (assert (zerop (calc-inversion-number #(1 2))))
  (assert (= 1 (calc-inversion-number #(2 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
;;;

;; i回目でx位(0-based)を x*50 + i位と考える
(defun main ()
  (let* ((n (read))
         (k (read))
         (grades (make-hash-table :test #'eq))
         (used (make-array 1000000 :element-type 'bit :initial-element 0))
         (dp (make-array 70000 :element-type 'uint32 :initial-element 0))
         (as (make-array (list n k) :element-type 'uint32))
         (a-poses (make-array n :element-type 'uint32 :initial-element 0)))
    (declare (uint16 n k))
    (dotimes (i n)
      (dotimes (j k)
        (setf (aref as i j) (- (read-fixnum) 1))))
    (dotimes (i n)
      (let (res
            stop)
        (dotimes (actual-grade k)
          (let* ((a (aref as i actual-grade))
                 (grade (+ (* actual-grade 50) i))
                 (prev-grade (gethash a grades))
                 (new-grade (if prev-grade
                                (min prev-grade grade)
                                grade))
                 (new-actual-grade (floor new-grade 50)))
            (declare (uint32 new-grade))
            ;; 順位データの更新
            (when prev-grade
              (bitree-update! dp prev-grade -1))
            (bitree-update! dp new-grade 1)
            (setf (gethash a grades) new-grade)
            (let* ((sup-number (bitree-sum dp new-grade))
                   ;; 今までで自分の順位以上の人の数+
                   ;; これから自分の順位より上になりえる人の数
                   (best-actual-grade (+ sup-number (* (- n i 1) new-actual-grade))))
              (if (< best-actual-grade k)
                  (progn
                    (unless stop
                      (setf (aref a-poses i) (+ actual-grade 1))) ;; 次の走査位置
                    (when (zerop (aref used a))
                      (setf (aref used a) 1)
                      (push (+ 1 a) res)))
                  (setq stop t)))))
        ;; 以前の選手を調べる
        (dotimes (old-i i)
          (loop (let ((a-pos (aref a-poses old-i)))
                  (when (= k a-pos)
                    (return))
                  (let* ((a (aref as old-i a-pos))
                         (grade (gethash a grades))
                         (sup-number (bitree-sum dp grade))
                         (actual-grade (floor grade 50))
                         (best-actual-grade (+ sup-number (* (- n i 1) actual-grade))))
                    (declare (uint32 grade))
                    (if (< best-actual-grade k)
                        (when (zerop (aref used a))
                          (setf (aref used a) 1)
                          (push (+ 1 a) res))
                        (return))))
                (incf (aref a-poses old-i))))
        (format t "~{~D~^ ~}~%" (sort res #'<))))))

#-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 11
1 2 3 4 5 6 7 8 9 10 11
1 2 15 14 13 16 17 18 19 20 21
"
    "1 2 3 4 5 6
7 13 14 15 16
"))
  (it.bese.fiveam:is
   (common-lisp-user::io-equal "4 5
1 2 3 4 5
2 1 3 4 5
1 2 3 4 5
2 1 3 4 5
"
    "1 2

3
4 5
")))

Submission Info

Submission Time
Task C - 決勝進出者
User sansaqua
Language Common Lisp (SBCL 1.1.14)
Score 100
Code Size 15468 Byte
Status AC
Exec Time 142 ms
Memory 31204 KiB

Judge Result

Set Name All
Score / Max Score 100 / 100
Status
AC × 76
Set Name Test Cases
All sample_01.txt, sample_02.txt, test_00.txt, test_01.txt, test_02.txt, test_03.txt, test_04.txt, test_05.txt, test_06.txt, test_07.txt, test_08.txt, test_09.txt, test_10.txt, test_11.txt, test_12.txt, test_13.txt, test_14.txt, test_15.txt, test_16.txt, test_17.txt, test_18.txt, test_19.txt, test_20.txt, test_21.txt, test_22.txt, test_23.txt, test_24.txt, test_25.txt, test_26.txt, test_27.txt, test_28.txt, test_29.txt, test_30.txt, test_31.txt, test_32.txt, test_33.txt, test_34.txt, test_35.txt, test_36.txt, test_37.txt, test_38.txt, test_39.txt, test_40.txt, test_41.txt, test_42.txt, test_43.txt, test_44.txt, test_45.txt, test_46.txt, test_47.txt, test_48.txt, test_49.txt, test_50.txt, test_51.txt, test_52.txt, test_53.txt, test_54.txt, test_55.txt, test_56.txt, test_57.txt, test_58.txt, test_59.txt, test_60.txt, test_61.txt, test_62.txt, test_63.txt, test_64.txt, test_65.txt, test_66.txt, test_67.txt, test_68.txt, test_69.txt, test_70.txt, test_71.txt, sample_01.txt, sample_02.txt
Case Name Status Exec Time Memory
sample_01.txt AC 124 ms 27108 KiB
sample_02.txt AC 124 ms 27104 KiB
test_00.txt AC 124 ms 27108 KiB
test_01.txt AC 125 ms 27108 KiB
test_02.txt AC 125 ms 27108 KiB
test_03.txt AC 124 ms 27108 KiB
test_04.txt AC 124 ms 27104 KiB
test_05.txt AC 124 ms 27104 KiB
test_06.txt AC 124 ms 27108 KiB
test_07.txt AC 124 ms 27108 KiB
test_08.txt AC 124 ms 27108 KiB
test_09.txt AC 124 ms 27104 KiB
test_10.txt AC 124 ms 27104 KiB
test_11.txt AC 124 ms 27108 KiB
test_12.txt AC 124 ms 27104 KiB
test_13.txt AC 124 ms 27108 KiB
test_14.txt AC 124 ms 27104 KiB
test_15.txt AC 124 ms 27108 KiB
test_16.txt AC 125 ms 27108 KiB
test_17.txt AC 125 ms 27108 KiB
test_18.txt AC 125 ms 27108 KiB
test_19.txt AC 125 ms 27112 KiB
test_20.txt AC 125 ms 27104 KiB
test_21.txt AC 125 ms 27108 KiB
test_22.txt AC 125 ms 27108 KiB
test_23.txt AC 125 ms 27108 KiB
test_24.txt AC 124 ms 27104 KiB
test_25.txt AC 124 ms 27112 KiB
test_26.txt AC 124 ms 27104 KiB
test_27.txt AC 124 ms 27108 KiB
test_28.txt AC 126 ms 27108 KiB
test_29.txt AC 124 ms 27112 KiB
test_30.txt AC 124 ms 27104 KiB
test_31.txt AC 124 ms 27108 KiB
test_32.txt AC 124 ms 27108 KiB
test_33.txt AC 124 ms 27108 KiB
test_34.txt AC 124 ms 27104 KiB
test_35.txt AC 125 ms 27112 KiB
test_36.txt AC 124 ms 27112 KiB
test_37.txt AC 124 ms 27108 KiB
test_38.txt AC 124 ms 27108 KiB
test_39.txt AC 124 ms 27104 KiB
test_40.txt AC 127 ms 27104 KiB
test_41.txt AC 125 ms 27108 KiB
test_42.txt AC 125 ms 27112 KiB
test_43.txt AC 125 ms 27112 KiB
test_44.txt AC 126 ms 27108 KiB
test_45.txt AC 125 ms 27108 KiB
test_46.txt AC 125 ms 27112 KiB
test_47.txt AC 125 ms 27108 KiB
test_48.txt AC 124 ms 27108 KiB
test_49.txt AC 124 ms 27112 KiB
test_50.txt AC 124 ms 27108 KiB
test_51.txt AC 124 ms 27104 KiB
test_52.txt AC 124 ms 27108 KiB
test_53.txt AC 125 ms 27108 KiB
test_54.txt AC 125 ms 27108 KiB
test_55.txt AC 126 ms 27108 KiB
test_56.txt AC 125 ms 27108 KiB
test_57.txt AC 125 ms 27108 KiB
test_58.txt AC 125 ms 27112 KiB
test_59.txt AC 125 ms 27108 KiB
test_60.txt AC 125 ms 27108 KiB
test_61.txt AC 125 ms 27104 KiB
test_62.txt AC 125 ms 27108 KiB
test_63.txt AC 125 ms 27108 KiB
test_64.txt AC 140 ms 27104 KiB
test_65.txt AC 141 ms 27108 KiB
test_66.txt AC 141 ms 27112 KiB
test_67.txt AC 141 ms 27108 KiB
test_68.txt AC 142 ms 27108 KiB
test_69.txt AC 142 ms 27104 KiB
test_70.txt AC 140 ms 27108 KiB
test_71.txt AC 141 ms 31204 KiB