【AtCoder ADT】
グリッド移動とビットマスク全探索
(E20260515_1)

関連記事

1. A – Buy a Pen

入力文字列と、:blueなどのキーワードシンボルで比較したかったのですが、うまくできず。
とりあえず、文字列比較で。

;; (min-pen-price 20 30 10 "Blue") ;=> 20
(defun min-pen-price (r g b color)
  (cond 
    ((string= color "Red") (min g b))
    ((string= color "Blue") (min r g))
    ((string= color "Green") (min r b))))

(defun main ()
  (princ (min-pen-price (read) (read) (read) (read-line))))

#-swank(main)Code language: Lisp (lisp)
1. A – Buy a Pen

2. B – Exact Price

基本的には X が 100 に割り切れるかで、あとは例外となる 0未満を除外しました。

(defun print-yesno (c)
  (declare (type boolean c))
  (princ (if c "Yes" "No")))

(defun main ()
  (let ((x (read)))
    (print-yesno (and (> x 0)
                      (= 0 (mod x 100))))))
#-swank(main)Code language: Lisp (lisp)
2. B – Exact Price

3. C – Grid Walk

グリッドを動く問題は、多いです。
インタープリタのようにコマンドを解釈し、有効なときだけ位置を更新しました。

行・列の座標系が、x-y座標と 90度 ずれていること、0起算と1起算に注意が必要ですね。

(defun make-grid (H W lines)
  (let ((grid (make-array (list H W) :element-type 'character
                                     :initial-element #\.)))
    (loop for line in lines
          for i below H
          do (loop for ch across line
                   for j below W
                   do (setf (aref grid i j) ch))
          finally (return grid))))

(defun next-pos (i j dir)
  (case dir
    (#\L (cons i (1- j)))
    (#\R (cons i (1+ j)))
    (#\U (cons (1- i) j))
    (#\D (cons (1+ i) j))))

(defun move-commands (H W i j grid commands)
  (loop for dir across commands
        with ci = (1- i)
        with cj = (1- j)
        for next = (next-pos ci cj dir)
        for ni = (car next)
        for nj = (cdr next)
        when (and (<= 0 ni (1- H))
                  (<= 0 nj (1- W))
                  (eql (aref grid ni nj) #\.))
          do (setf ci ni
                   cj nj)
        finally (return (cons ci cj))))

(defun main ()
  (let* ((H (read))
         (W (read))
         (Si (read))
         (Sj (read))
         (grid (make-grid H W (loop repeat H collect (read-line))))
         (commands (read-line))
         (pos (move-commands H W Si Sj grid commands)))
    (format t "~a ~a" (1+ (car pos)) (1+ (cdr pos)))))
#-swank(main)
Code language: Lisp (lisp)
3. C – Grid Walk

この問題までで時間切れになりました。

3. C – Grid Walk

4. D – Perfect

この問題では、イベントの後半の数値は重複しない約束なので無視でき、ただそれぞれの参加者の解答数をカウントしていけばよいことになります。

(defun perfect-participants (N M events)
  (loop for (a b) in events
        with memo = (make-array N :initial-element 0)
        do (incf (aref memo (1- a)))
        when (= M (aref memo (1- a)))
          collect a))

;; (perfect-participants 3 2 '((1 1) (3 2) (2 1) (3 1) (1 2)))
;;=> (3 1)


(defun main ()
  (let* ((N (read))
         (M (read))
         (K (read))
         (events (loop repeat K
                       collect (list (read) (read)))))
    (loop for p in (perfect-participants N M events)
          do (princ p)
             (princ #\space))))
#-swank(main)Code language: Lisp (lisp)
4. D – Perfect

5. E – Keys

キーの有無をビットパターンで表現し、それを総当り法で条件に適合しているものを求めました。
はじめは、simple-bit-vectorで解決しようと思いましたが、ビット全探索では数値の方が実装しやすかったです。

;; (check-keys/naive 3 2 ts #b101) ;=> T
;; (check-keys/naive 3 2 ts #b110) ;=> T
;; (check-keys/naive 3 2 ts #b111) ;=> NIL
(defun check-keys/naive (N K tests pattern)
  (declare (ignore N))
  (loop for test in tests
        for keys = (car test)
        for r = (cdr test)
        always (cond
                 ((eq r 'O)
                  (>= (count-pattern pattern keys) K))
                 ((eq r 'X)
                  (< (count-pattern pattern keys) K))
                 (t t))))

;; (count-keys/naive 3 2 ts) ;=> 2
(defun count-keys/naive (N K tests)
  (loop for pattern from 0 below (expt 2 N)
        count (check-keys/naive N K tests pattern)))

;; (count-pattern #b101 #b111) ;=> 2
;; pattern is expressed by bit-mask
(defun count-pattern (pattern keys)
  (count-bit-mask (logand pattern keys)))

;; (count-bit-mask #b11010) ;=> 3
(defun count-bit-mask (mask)
  (loop for i below (integer-length mask)
        count (logbitp i mask)))

(defun set-flag (mask i)
  (logior mask (ash 1 i)))

;; ((#b111 . O) (#b110 . X))
(defun read-tests (N M)
  (declare (ignore N))
  (loop repeat M
        for C = (read)
        for keys = (loop repeat C
                         with mask = 0
                         for k = (read)
                         do (setf mask (set-flag mask (1- k)))
                         finally (return mask))
        for ret = (read)
        collect (cons keys ret)))

(defun main ()
  (let* ((N (read))
         (M (read))
         (K (read))
         (tests (read-tests N M)))
    (princ (count-keys/naive N K tests))))
#-swank(main)Code language: Lisp (lisp)

素朴な方法なので時間内に解けないと思ったのですが、 N15N \leq 15 の制約のため解けました。

5. E – Keys

時間がかかりましたが、全部解けました。

5. E – Keys