提出 #7080100


ソースコード 拡げる

;; -*- coding: utf-8 -*-
(eval-when (:compile-toplevel :load-toplevel :execute)
  (defparameter OPT
    #+swank '(optimize (speed 3) (safety 2))
    #-swank '(optimize (speed 3) (safety 0) (debug 0)))
  #+swank (ql:quickload '(:cl-debug-print :fiveam))
  #-swank (set-dispatch-macro-character #\# #\> (lambda (s c p) (declare (ignore c p)) (read s nil (values) t))))
#+swank (cl-syntax:use-syntax cl-debug-print:debug-print-syntax)
#-swank (disable-debugger) ; for CS Academy

;; BEGIN_INSERTED_CONTENTS
(declaim (inline get-2dcumul))
(defun get-2dcumul (cumul-table i0 j0 i1 j1)
  "Returns the cumulative sum of the region given by the rectangle [i0, i1)*[j0,
j1). CUMUL-TABLE must be appropriately initialized beforehand:
i.e. CUMUL-TABLE[i][j] = sum of the region given by the regtangle [0, i)*[0,
j)."
  (+ (- (aref cumul-table i1 j1)
        (aref cumul-table i0 j1)
        (aref cumul-table i1 j0))
     (aref cumul-table i0 j0)))

;;;
;;; 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 return value to
;; a hash-table when evaluating (ADD A B) 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 the cache is 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 the 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 for `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.
;;

;; 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-tracing (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) (eql 'declare (car (if (listp form) form (list 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
                               (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-tracing name args res)
                       res)))
               (make-reset-form (cache-type)
                 (case cache-type
                   (:hash-table `(setf ,cache (make-hash-table ,@rest-attribs)))
                   (:array `(prog1 nil
                              (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-caches (cache-specs def-form)
  "DEF-FORM := definition form with LABELS or FLET.

 (with-caches (cache-spec1 cache-spec2)
   (labels ((f (x) ...) (g (y) ...))))
is equivalent to the line up of
 (with-cache cache-spec1 (labels ((f (x) ...))))
and
 (with-cache cache-spec2 (labels ((g (y) ...)))) "
  (assert (member (car def-form) '(labels flet)))
  (let (cache-symbol-list cache-form-list cache-type-list name-alias-list make-reset-name-list make-reset-form-list make-cache-querier-list)
    (dolist (cache-spec (reverse cache-specs))
      (multiple-value-bind (cache-symbol cache-form cache-type name-alias
                            make-reset-name make-reset-form make-cache-querier)
          (%parse-cache-form cache-spec)
        (push cache-symbol cache-symbol-list)
        (push cache-form cache-form-list)
        (push cache-type cache-type-list)
        (push name-alias name-alias-list)
        (push make-reset-name make-reset-name-list)
        (push make-reset-form make-reset-form-list)
        (push make-cache-querier make-cache-querier-list)))
    (labels ((def-name (def) (first def))
             (def-args (def) (second def))
             (def-body (def) (cddr def)))
      (destructuring-bind (_ definitions &body labels-body) def-form
        (declare (ignore _))
        `(let ,(loop for cache-symbol in cache-symbol-list
                     for cache-form in cache-form-list
                     collect `(,cache-symbol ,cache-form))
           (,(car def-form)
            (,@(loop for def in definitions
                     for cache-type in cache-type-list
                     for make-reset-name in make-reset-name-list
                     for make-reset-form in make-reset-form-list
                     collect `(,(funcall make-reset-name (def-name def)) ()
                               ,(funcall make-reset-form cache-type)))
             ,@(loop for def in definitions
                     for cache-type in cache-type-list
                     for name-alias in name-alias-list
                     for make-cache-querier in make-cache-querier-list
                     collect `(,(def-name def) ,(def-args def)
                               ,@(%extract-declarations (def-body def))
                               (labels ((,name-alias ,(def-args def) ,@(def-body def)))
                                 (declare (inline ,name-alias))
                                 ,(funcall make-cache-querier cache-type (def-name def) (def-args def))))))
            (declare (ignorable ,@(loop for def in definitions
                                        for make-reset-name in make-reset-name-list
                                        collect `#',(funcall make-reset-name
                                                             (def-name def)))))
            ,@labels-body))))))

(defmacro buffered-read-line (&optional (buffer-size 30) (in '*standard-input*) (term-char #\Space))
  "Reads ASCII inputs and returns two values: the string and the end
position. Note that the returned string will be reused if this form is executed
more than once.

This macro calls READ-BYTE to read characters though it calls READ-CHAR instead
on SLIME because SLIME's IO is not bivalent."
  (let ((buffer (gensym))
        (character (gensym))
        (idx (gensym)))
    `(let* ((,buffer (load-time-value (make-string ,buffer-size :element-type 'base-char))))
       (declare (simple-base-string ,buffer)
                (inline read-byte))
       (loop for ,character of-type base-char =
                ,(if (member :swank *features*)
                     `(read-char ,in nil #\Newline) ; on SLIME
                     `(code-char (read-byte ,in nil #.(char-code #\Newline))))
             for ,idx from 0
             until (char= ,character #\Newline)
             do (setf (schar ,buffer ,idx) ,character)
             finally (when (< ,idx ,buffer-size)
                       (setf (schar ,buffer ,idx) ,term-char))
                     (return (values ,buffer ,idx))))))

(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 main ()
  (declare #.OPT)
  (let* ((h (read))
         (w (read))
         (cumuls (make-array '(186 186) :element-type 'uint32 :initial-element 0)))
    (declare (uint8 h w))
    (dotimes (i h)
      (let ((line (buffered-read-line 185)))
        (dotimes (j w)
          (when (char= #\# (aref line j))
            (setf (aref cumuls (+ i 1) (+ j 1)) 1)))))
    (dotimes (i (+ h 1))
      (dotimes (j w)
        (incf (aref cumuls i (+ j 1)) (aref cumuls i j))))
    (dotimes (j (+ w 1))
      (dotimes (i h)
        (incf (aref cumuls (+ i 1) j) (aref cumuls i j))))
    (with-caches ((:array (186 186 186 20)
                   :element-type 'uint8
                   :initial-element #xff)
                  (:array (186 186 186 20)
                   :element-type 'uint8
                   :initial-element #xff))
      (labels
          ((f (y1 x1 y2 c)
             (declare (uint8 y1 x1 y2 c))
             (if (zerop c)
                 (sb-int:named-let bisect ((ok x1) (ng (+ w 1)))
                   (declare (uint8 ok ng))
                   (if (<= (- ng ok) 1)
                       ok
                       (let* ((mid (floor (+ ok ng) 2))
                              (sum (get-2dcumul cumuls y1 x1 y2 mid)))
                         (if (or (= sum (* (- y2 y1) (- mid x1)))
                                 (= sum 0))
                             (bisect mid ng)
                             (bisect ok mid)))))
                 (let ((res1 (f y1 (f y1 x1 y2 (- c 1)) y2 (- c 1)))
                       (res2 (sb-int:named-let bisect ((ok x1) (ng (+ w 1)))
                               (declare (uint8 ok ng))
                               (if (<= (- ng ok) 1)
                                   ok
                                   (let* ((mid (floor (+ ok ng) 2))
                                          (val (g (g y1 x1 mid (- c 1)) x1 mid (- c 1))))
                                     (if (>= val y2)
                                         (bisect mid ng)
                                         (bisect ok mid)))))))
                   (max res1 res2))))
           (g (y1 x1 x2 c)
             (declare (uint8 y1 x1 x2 c))
             (if (zerop c)
                 (sb-int:named-let bisect ((ok y1) (ng (+ h 1)))
                   (declare (uint8 ok ng))
                   (if (<= (- ng ok) 1)
                       ok
                       (let* ((mid (floor (+ ok ng) 2))
                              (sum (get-2dcumul cumuls y1 x1 mid x2)))
                         (if (or (= sum (* (- mid y1) (- x2 x1)))
                                 (= sum 0))
                             (bisect mid ng)
                             (bisect ok mid)))))
                 (let ((res1 (g (g y1 x1 x2 (- c 1)) x1 x2 (- c 1)))
                       (res2 (sb-int:named-let bisect ((ok y1) (ng (+ h 1)))
                               (declare (uint8 ok ng))
                               (if (<= (- ng ok) 1)
                                   ok
                                   (let* ((mid (floor (+ ok ng) 2))
                                          (val (f y1 (f y1 x1 mid (- c 1)) mid (- c 1))))
                                     (if (>= val x2)
                                         (bisect mid ng)
                                         (bisect ok mid)))))))
                   (max res1 res2)))))
        (dotimes (c 20)
          (let  ((x (f 0 0 h c)))
            (when (= x w)
              (println c)
              (return-from main))))))))

#-swank (main)

提出情報

提出日時
問題 D - Complexity
ユーザ sansaqua
言語 Common Lisp (SBCL 1.1.14)
得点 1000
コード長 16222 Byte
結果 AC
実行時間 4423 ms
メモリ 297828 KiB

ジャッジ結果

セット名 Sample All
得点 / 配点 0 / 0 1000 / 1000
結果
AC × 2
AC × 42
セット名 テストケース
Sample sample01.txt, sample02.txt
All sample01.txt, sample02.txt, in01.txt, in02.txt, in03.txt, in04.txt, in05.txt, in06.txt, in07.txt, in08.txt, in09.txt, in10.txt, in11.txt, in12.txt, in13.txt, in14.txt, in15.txt, in16.txt, in17.txt, in18.txt, in19.txt, in20.txt, in21.txt, in22.txt, in23.txt, in24.txt, in25.txt, in26.txt, in27.txt, in28.txt, in29.txt, in30.txt, in31.txt, in32.txt, in33.txt, in34.txt, in35.txt, in36.txt, in37.txt, in38.txt, sample01.txt, sample02.txt
ケース名 結果 実行時間 メモリ
in01.txt AC 2510 ms 297828 KiB
in02.txt AC 3081 ms 285288 KiB
in03.txt AC 2864 ms 285284 KiB
in04.txt AC 3331 ms 285284 KiB
in05.txt AC 2424 ms 285280 KiB
in06.txt AC 2440 ms 285284 KiB
in07.txt AC 4215 ms 285284 KiB
in08.txt AC 4423 ms 285280 KiB
in09.txt AC 224 ms 285280 KiB
in10.txt AC 223 ms 285284 KiB
in11.txt AC 224 ms 285284 KiB
in12.txt AC 224 ms 285284 KiB
in13.txt AC 225 ms 285284 KiB
in14.txt AC 225 ms 285288 KiB
in15.txt AC 225 ms 285288 KiB
in16.txt AC 225 ms 285284 KiB
in17.txt AC 349 ms 285284 KiB
in18.txt AC 265 ms 285284 KiB
in19.txt AC 358 ms 285284 KiB
in20.txt AC 265 ms 285284 KiB
in21.txt AC 952 ms 285280 KiB
in22.txt AC 222 ms 285280 KiB
in23.txt AC 224 ms 285284 KiB
in24.txt AC 406 ms 285284 KiB
in25.txt AC 394 ms 285280 KiB
in26.txt AC 779 ms 285288 KiB
in27.txt AC 695 ms 285284 KiB
in28.txt AC 911 ms 285284 KiB
in29.txt AC 227 ms 285284 KiB
in30.txt AC 227 ms 285288 KiB
in31.txt AC 263 ms 285284 KiB
in32.txt AC 270 ms 285280 KiB
in33.txt AC 328 ms 285284 KiB
in34.txt AC 319 ms 285284 KiB
in35.txt AC 679 ms 285288 KiB
in36.txt AC 642 ms 285288 KiB
in37.txt AC 3385 ms 285284 KiB
in38.txt AC 3325 ms 285284 KiB
sample01.txt AC 222 ms 285288 KiB
sample02.txt AC 223 ms 285288 KiB