提出 #9890003


ソースコード 拡げる

(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"
  (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))))))))

;;;
;;; Calculate a^n on any monoids in O(log(n)) time
;;;

;; (declaim (inline power))
;; (defun power (base exponent op identity)
;;   "OP := binary operation (comprising a monoid)
;; IDENTITY := identity element w.r.t. OP"
;;   (declare ((integer 0) exponent))
;;   (labels ((recur (x p)
;;              (declare ((integer 0 #.most-positive-fixnum) p))
;;              (cond ((zerop p) identity)
;;                    ((evenp p) (recur (funcall op x x) (ash p -1)))
;;                    (t (nth-value 0 (funcall op x (recur x (- p 1)))))))
;;            (recur-big (x p)
;;              (declare ((integer 0) p))
;;              (cond ((zerop p) identity)
;;                    ((evenp p) (recur-big (funcall op x x) (ash p -1)))
;;                    (t (nth-value 0 (funcall op x (recur-big x (- p 1))))))))
;;     (typecase exponent
;;       (fixnum (recur base exponent))
;;       (otherwise (recur-big base exponent)))))

(declaim (inline decompose-to-cycles))
(defun decompose-to-cycles (permutation)
  "Returns the list of all the cyclic permutations in a given permutation of {0,
1, ..., N-1}"
  (declare (vector permutation))
  (let* ((n (length permutation))
         result
         (visited (make-array n :element-type 'bit :initial-element 0)))
    (dotimes (init n)
      (when (zerop (sbit visited init))
        (push (loop for x = init then (aref permutation x)
                    until (= (sbit visited x) 1)
                    collect x
                    do (setf (sbit visited x) 1))
              result)))
    result))

(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 perm* (perm1 perm2)
;;   (let* ((n (length perm1))
;;          (res (make-array n :element-type 'uint31)))
;;     (dotimes (i n)
;;       (setf (aref res i) (aref perm2 (aref perm1 i))))
;;     res))

;; (defun perm-power (perm exp)
;;   (let ((iden (make-array (length perm) :element-type 'uint31)))
;;     (dotimes (i (length perm))
;;       (setf (aref iden i) i))
;;     (power perm exp #'perm* iden)))

(declaim (inline lastcar))
(defun lastcar (list)
  (car (last list)))

(defun main ()
  (let* ((n (read))
         (k (read))
         (as (make-array n :element-type 'uint31))
         (res (make-array n :element-type 'uint31)))
    (declare (uint16 n k))
    (dotimes (i n)
      (setf (aref as i) (- (read-fixnum) 1)))
    (let ((cycles (decompose-to-cycles as))
          (cycle-table (make-array (+ n 1) :element-type 'list :initial-element nil))
          (num-table (make-array (+ n 1) :element-type 'uint31 :initial-element 0)))
      (dolist (cycle cycles)
        (let ((len (length (the list cycle))))
          (incf (aref num-table len))
          (push cycle (aref cycle-table len))))
      (labels ((no () (println 0) (return-from main))
               (render-cycle (len num)
                 (let* ((total (* len num))
                        (large-perm (make-array total :element-type 'uint31)))
                   (dbg len num total)
                   #>large-perm
                   (let ((index 0))
                     (declare (uint31 index))
                     (dotimes (_ num)
                       (let ((cycle (pop (aref cycle-table len))))
                         #>cycle
                         (dotimes (_ len)
                           (let ((v (pop cycle)))
                             (setf (aref large-perm index) v)
                             (setq index (mod (+ index k) total))))
                         (setq index (mod (+ index 1) total)))))
                   #>large-perm
                   (dotimes (i (- total 1))
                     (setf (aref res (aref large-perm i))
                           (aref large-perm (+ i 1))))
                   (setf (aref res (aref large-perm (- total 1)))
                         (aref large-perm 0))
                   #>res)))
        (loop for l from 1 to n
              for l-num = (aref num-table l)
              for perimtr-set = (make-array 0 :fill-pointer 0 :element-type 'uint31)
              unless (zerop l-num)
              do (loop for length from 1 to (* l l-num)
                       when (= length (* (gcd length k) l))
                       do (vector-push-extend length perimtr-set))
                 ;; perimtr-setの中の周長Lを使うとgcd(L, k)個の巡回置換が消費で
                 ;; きる。重複を許して自由にこれらの長さを使ってl-num個の巡回置
                 ;; 換をちょうど消費したい(重複あり部分和問題)
                 (let* ((set-size (length perimtr-set))
                        (dp (make-array (list (+ 1 set-size) (+ l-num 1))
                                        :element-type 'bit
                                        :initial-element 0)))
                   (setf (aref dp 0 0) 1)
                   (loop for x from 1 to set-size
                         for perimeter = (aref perimtr-set (- x 1))
                         for consum = (gcd perimeter k)
                         do (loop for y from 0 to l-num
                                  do (setf (aref dp x y)
                                           (logior (if (< y consum)
                                                       0
                                                       (aref dp x (- y consum)))
                                                   (aref dp (- x 1) y)))))
                   (when (zerop (aref dp set-size l-num))
                     (no))
                   (sb-int:named-let recur ((x set-size) (y l-num))
                     (declare (uint31 x y))
                     (unless (and (zerop x) (zerop y))
                       (if (and (> x 0)
                                (= 1 (aref dp (- x 1) y)))
                           (recur (- x 1) y)
                           (let* ((perimeter (aref perimtr-set (- x 1)))
                                  (consum (gcd perimeter k)))
                             (declare (uint31 perimeter consum))
                             (assert (= 1 (aref dp x (- y consum))))
                             (render-cycle l consum)
                             (recur x (- y consum))))))))))
    (loop for x across res
          do (println (+ x 1)))))

#-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
  (5am:is (io-equal "3 5
3
1
2
"
                    "2
3
1
"))
  (5am:is (io-eqaul "4 4
2
1
4
3
"
                    "0
")))

提出情報

提出日時
問題 circuit - 電気回路の結線 (Circuit)
ユーザ sansaqua
言語 Common Lisp (SBCL 1.1.14)
得点 100
コード長 11129 Byte
結果 AC
実行時間 530 ms
メモリ 35044 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 01
Set02 02
Set03 03
Set04 04
Set05 05
ケース名 結果 実行時間 メモリ
01 AC 530 ms 35044 KiB
02 AC 161 ms 25056 KiB
03 AC 117 ms 23012 KiB
04 AC 160 ms 25056 KiB
05 AC 161 ms 25060 KiB