提出 #7947960


ソースコード 拡げる

;; -*- coding: utf-8 -*-
(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)) (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 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
;;;

(defstruct (sliding-window (:constructor make-sliding-window
                               (size &aux
                                     (times (make-array size :element-type 'fixnum))
                                     (values (make-array size :element-type 'fixnum))))
                           (:conc-name %swindow-)
                           (:copier nil))
  (front-pos 0 :type (integer 0 #.most-positive-fixnum))
  (end-pos -1 :type (integer -1 #.most-positive-fixnum))
  (times nil :type (simple-array fixnum (*)))
  (values nil :type (simple-array fixnum (*))))

(defun %swindow-push-back (time value sw)
  (let ((new-end-pos (+ 1 (%swindow-end-pos sw))))
    (setf (aref (%swindow-times sw) new-end-pos) time
          (aref (%swindow-values sw) new-end-pos) value
          (%swindow-end-pos sw) new-end-pos)))

(defun %swindow-pop-back (sw)
  (decf (%swindow-end-pos sw)))

(defun %swindow-pop-front (sw)
  (incf (%swindow-front-pos sw)))

(declaim (inline swindow-extend))
(defun swindow-extend (time value sw order)
  "ORDER := #'< => minimum
ORDER := #'> => maximum"
  (let ((values (%swindow-values sw)))
    (loop while (and (<= (%swindow-front-pos sw) (%swindow-end-pos sw))
                     (not (funcall order
                                   (aref values (%swindow-end-pos sw))
                                   value)))
          do (%swindow-pop-back sw))
    (%swindow-push-back time value sw)))

(declaim (inline swindow-shrink))
(defun swindow-shrink (time sw)
  (let ((times (%swindow-times sw)))
    (loop while (and (<= (%swindow-front-pos sw) (%swindow-end-pos sw))
                     (< (aref times (%swindow-front-pos sw)) time))
          do (%swindow-pop-front sw))))

(declaim (inline swindow-empty-p))
(defun swindow-empty-p (sw)
  (> (%swindow-front-pos sw) (%swindow-end-pos sw)))

(declaim (inline swindow-get-opt))
(defun swindow-get-opt (sw)
  (let ((front-pos (%swindow-front-pos sw)))
    (aref (%swindow-values sw) front-pos)))

(declaim (inline %median3))
(defun %median3 (x y z order)
  (if (funcall order x y)
      (if (funcall order y z)
          y
          (if (funcall order z x)
              x
              z))
      (if (funcall order z y)
          y
          (if (funcall order x z)
              x
              z))))

(declaim (inline quicksort2))
(defun quicksort2 (vector order)
  (declare ((simple-array fixnum (*)) vector))
  (labels
      ((recur (left right)
         (when (< left right)
           (let* ((l left)
                  (r right)
                  (pivot (%median3 (aref vector l)
                                   (aref vector (ash (ash (+ l r) -2) 1))
                                   (aref vector r)
                                   order)))
             (declare ((integer 0 #.most-positive-fixnum) l r))
             (loop (loop while (funcall order (aref vector l) pivot)
                         do (incf l 2))
                   (loop while (funcall order pivot (aref vector r))
                         do (decf r 2))
                   (when (>= l r)
                     (return))
                   (rotatef (aref vector l) (aref vector r))
                   (rotatef (aref vector (+ l 1)) (aref vector (+ r 1)))
                   (incf l 2)
                   (decf r 2))
             (recur left (- l 2))
             (recur (+ r 2) right)))))
    (recur 0 (- (length vector) 2))
    vector))

;; 市場価値の和をxA, xB、貴重度の和をyA, yBとするとき、xAとxBの差を一定以内に収
;; めつつ、yAとyBの差をできるだけ大きくする問題になる。財宝をS1とS2にわける。S1
;; のとある財宝の取り方の市場価値の差がΔx、貴重度の差がΔyであるとする。S2のす
;; べての財宝の取り方を市場価値の差の昇順でソートしておくとする。この時、市場価
;; 値の差が[-D-Δx, D-Δx]に入っているような(S2からの)取り方について、貴重度の
;; 最大値がわかればよい。

(defun main ()
  (declare #.OPT)
  (let* ((n (read))
         (d (read))
         (size1 (ceiling n 2))
         (size2 (- n size1))
         (xs1 (make-array size1 :element-type 'uint62))
         (ys1 (make-array size1 :element-type 'uint62))
         (xs2 (make-array size2 :element-type 'uint62))
         (ys2 (make-array size2 :element-type 'uint62)))
    (declare ((integer 1 30) n)
             (uint62 d))
    (dotimes (i size1)
      (setf (aref xs1 i) (read)
            (aref ys1 i) (read)))
    (dotimes (i size2)
      (setf (aref xs2 i) (read)
            (aref ys2 i) (read)))
    (let ((xydeltas1 (make-array (ash (expt 3 size1) 1)
                                 :element-type 'fixnum))
          (xydeltas2 (make-array (ash (expt 3 size2) 1)
                                 :element-type 'fixnum)))
      (declare ((simple-array fixnum (*)) xydeltas1 xydeltas2))
      (let ((pointer 0))
        (declare (uint31 pointer))
        (sb-int:named-let recur ((pos 0) (xdelta 0) (ydelta 0))
          (declare (fixnum pos xdelta ydelta))
          (if (= pos size1)
              (setf (aref xydeltas1 pointer) xdelta
                    (aref xydeltas1 (+ 1 pointer)) ydelta
                    pointer (+ 2 pointer))
              (progn (recur (+ pos 1)
                            (+ xdelta (aref xs1 pos))
                            (+ ydelta (aref ys1 pos)))
                     (recur (+ pos 1) xdelta ydelta)
                     (recur (+ pos 1)
                            (- xdelta (aref xs1 pos))
                            (- ydelta (aref ys1 pos)))))))
      (let ((pointer 0))
        (declare (uint31 pointer))
        (sb-int:named-let recur ((pos 0) (xdelta 0) (ydelta 0))
          (declare (fixnum pos xdelta ydelta))
          (if (= pos size2)
              (setf (aref xydeltas2 pointer) xdelta
                    (aref xydeltas2 (+ 1 pointer)) ydelta
                    pointer (+ 2 pointer))
              (progn (recur (+ pos 1)
                            (- xdelta (aref xs2 pos))
                            (- ydelta (aref ys2 pos)))
                     (recur (+ pos 1) xdelta ydelta)
                     (recur (+ pos 1)
                            (+ xdelta (aref xs2 pos))
                            (+ ydelta (aref ys2 pos)))))))
      (setf xydeltas1 (quicksort2 xydeltas1 #'>)
            xydeltas2 (quicksort2 xydeltas2 #'<))
      (let ((sw (make-sliding-window (expt 3 size2)))
            (res 0)
            (pos 0)
            (len (* 2 (expt 3 size2))))
        (declare (uint62 res pos len))
        ;; [-D-Δx, D-Δx]
        (loop for idx below (* 2 (expt 3 size1)) by 2
              for xdelta1 = (aref xydeltas1 idx)
              for ydelta1 = (aref xydeltas1 (+ idx 1))
              for sup of-type fixnum = (- d xdelta1)
              for inf of-type fixnum = (- (- d) xdelta1)
              do (loop
                   (when (= pos len)
                     (return))
                   (let* ((xdelta2 (aref xydeltas2 pos))
                          (ydelta2 (aref xydeltas2 (+ pos 1))))
                     (declare (fixnum xdelta2 ydelta2))
                     (when (> xdelta2 sup)
                       (return))
                     (swindow-extend xdelta2 ydelta2 sw #'>)
                     (incf pos 2)))
                 (swindow-shrink inf sw)
                 (unless (swindow-empty-p sw)
                   (let ((max (swindow-get-opt sw)))
                     (setq res (max res (+ ydelta1 max))))))
        (println res)))))

#-swank (main)

提出情報

提出日時
問題 F - 財宝 (Treasures)
ユーザ sansaqua
言語 Common Lisp (SBCL 1.1.14)
得点 100
コード長 9096 Byte
結果 AC
実行時間 3789 ms
メモリ 521056 KiB

ジャッジ結果

セット名 set01 set02 set03 set04 set05
得点 / 配点 20 / 20 20 / 20 20 / 20 20 / 20 20 / 20
結果
AC × 1
AC × 1
AC × 1
AC × 1
AC × 1
セット名 テストケース
set01 data1
set02 data2
set03 data3
set04 data4
set05 data5
ケース名 結果 実行時間 メモリ
data1 AC 115 ms 23008 KiB
data2 AC 3487 ms 521056 KiB
data3 AC 3789 ms 516964 KiB
data4 AC 2397 ms 328420 KiB
data5 AC 2454 ms 326372 KiB