AtCoder adt_easy_20260505_2

関連記事

1. A – First Contest of t Year(WA 2)

;; (next-year-contest-day 7 365 4) ; => 3
;; (next-year-contest-day 7 10 5) ; => 2
;; F mod W ≡ N + D mod W
(defun next-year-contest-day (w d f)
  (mod (- f d) w))


(defun main ()
  (let ((w 7)
        (d (read))
        (f (read)))
    (princ (next-year-contest-day w d f))))
#-swank(main)
Code language: Lisp (lisp)
1. A – First Contest of t Year(WA 2)

1.1. 割り切れる場合は7になる

;; (next-year-contest-day 7 365 4) ; => 3
;; (next-year-contest-day 7 10 5) ; => 2
;; (next-year-contest-day 7 10 3) ; => 7 (/= 0)
;; F mod W ≡ N + D mod W
(defun next-year-contest-day (w d f)
  (let ((n (mod (- f d) w)))
    (cond
      ((zerop n) w)
      (t n))))

(defun main ()
  (let ((w 7)
        (d (read))
        (f (read)))
    (princ (next-year-contest-day w d f))))
#-swank(main)
Code language: Lisp (lisp)
1.1. 割り切れる場合は7になる

2. B – Intersection

;; (length-painted-both 0 3 1 5)  ;=> 2
;; (length-painted-both 0 1 4 5) ;=> 0
;; (length-painted-both 0 3 3 7) ;=> 0
(defun length-painted-both (L1 R1 L2 R2)
  (cond
    ((<= R1 L2) 0)
    ((<= R2 L1) 0)
    (t (- (min R1 R2) (max L1 L2)))))

(defun main ()
  (princ (length-painted-both
          (read) (read) (read) (read))))
#-swank(main)Code language: Lisp (lisp)
2. B – Intersection

3. C – Strawberries

;; (consecutive-healthy-tooth "OOXOOOO") ;=> (2 4)
(defun consecutive-healthy-tooth (str)
  (loop for ch across str
        with lst = '()
        with cnt = 0
        when (eql ch #\O)
          do (incf cnt)
        when (and (eql ch #\X)
                  (> cnt 0))
          do (push cnt lst)
             (setf cnt 0)
        finally (when (> cnt 0)
                  (push cnt lst))
                (return (nreverse lst))))

;; (max-strawberries-eaten 3 "OOXOOOO") ; => 1
;; (max-strawberries-eaten 2 "OXXOOOXOOOOX") ; => 3
;; (max-strawberries-eaten 5 "XXOOOOOOOOXXOOOOOXXXXX") ; => 2
(defun max-strawberries-eaten (k str)
  (let ((lst (consecutive-healthy-tooth str)))
    (loop for n in lst
          sum (floor n k))))


(defun main ()
  (let ((N (read))
        (K (read))
        (S (read-line)))
    (declare (ignore N))
    (princ (max-strawberries-eaten K S))))

#-swank(main)Code language: Lisp (lisp)
3. C – Strawberries
3. C – Strawberries

4. D – TaK Code

グリッドの最大サイズが100×100なので、素直に条件を判定しました。

(defun make-grid (N M lines)
  (let ((grid (make-array (list N M)
                          :element-type 'bit
                          :initial-element 0)))
    (loop for str in lines
          for row below N
          do (loop for ch across str
                   for col below M
                   do (setf (aref grid row col)
                            (if (eql ch #\#) 1 0)))
          finally (return grid))))

;; (valid-tak-code-at-p 19 18 *grid* 0 0) ;=> T
;; (valid-tak-code-at-p 19 18 *grid* 1 1) ;=> NIL
(defun valid-tak-code-at-p (N M grid row col)
  (cond ((and (<= 0 row (- N 9))
              (<= 0 col (- M 9)))
         (and
          (= 0 (aref grid (+ row 3) (+ col 3)))
          (= 0 (aref grid (+ row 5) (+ col 5)))
          (loop for i from 0 to 2
                always (= 0 (aref grid (+ row i)
                                  (+ col 3)))
                always (= 0 (aref grid (+ row i 6)
                                  (+ col 5)))
                always (= 0 (aref grid (+ row 3)
                                  (+ col i)))
                always (= 0 (aref grid (+ row 5)
                                  (+ col i 6)))
                always (loop for j from 0 to 2
                            always (= 1 (aref grid
                                              (+ row i)
                                              (+ col j)))
                            always (= 1 (aref grid
                                              (+ row i 6)
                                              (+ col j 6)))))))
        (t nil)))

;; (satisfies-ij-list 19 18 *grid*)
;; => ((0 0) (0 9) (6 6) (9 1))
(defun satisfies-ij-list (N M grid)
  (loop for i below N
        append (loop for j below M
                     when (valid-tak-code-at-p N M grid i j)
                       collect (list i j))))

(defun read-lines (M)
  (loop repeat M collect (read-line)))

(defun main ()
  (let* ((N (read))
        (M (read))
        (Sn (read-lines N))
        (grid (make-grid N M Sn)))
    (loop for (i j) in (satisfies-ij-list N M grid)
          do (format t "~a ~a~%" (1+ i) (1+ j)))))
#-swank(main)
Code language: Lisp (lisp)
4. D – TaK Code

5. E – 1111gal password(197ms)

最初は、シンプルな再帰で解きました。

(defparameter *prime* 998244353)
;; (satisfied-patterns/rec 4)  ;=> 203
(defun satisfied-patterns/rec (N)
  (labels ((rec (N d)
             (mod (cond
                    ((= N 0) 0)
                    ((= N 1) 1)
                    ((= d 1) (+ (rec (1- N) 1)
                                (rec (1- N) 2)))
                    ((= d 9) (+ (rec (1- N) 8)
                                (rec (1- N) 9)))
                    (t (+ (rec (1- N) (1- d))
                          (rec (1- N) d)
                          (rec (1- N) (1+ d)))))
                  *prime*)))
    (loop for digit from 1 to 9
          sum (rec N digit))))Code language: JavaScript (javascript)

しかし、再計算が多く時間がかかりますし、Nが1,000,000だと、スタックオーバーフローになってしまいました。

5. E – 1111gal password(197ms)

次に、ハッシュテーブルでdp[N, d] を記録する方法を取っていましたが、これも N = 1,000,000 だとTLEでした。

そこで、動的計画法で prev と now の2つの配列を順次更新していくようにして、解くことができました。

(defparameter *prime* 998244353)
(defun satisfied-highest (N d prev now)
  (setf (aref now d)
        (mod 
         (cond
           ((= N 0) 0)
           ((= N 1) 1)
           ((= d 1) (+ (aref prev 1)
                       (aref prev 2)))
           ((= d 9) (+ (aref prev 8)
                       (aref prev 9)))
           ( t (+ (aref prev (1- d))
                  (aref prev d)
                  (aref prev (1+ d)))))
         *prime*)))

;; (satisfied-patterns 4) ; => 203
;; (satisfied-patterns 1000000) ;=> 248860093
(defun satisfied-patterns (N)
  (let ((now (make-array 10 :element-type 'fixnum
                            :initial-element 0))
        (prev (make-array 10 :element-type 'fixnum
                             :initial-element 0)))
    (loop for i from 1 to (1- N)
          do (loop for d from 1 to 9
                   do (satisfied-highest i d prev now))
          do (loop for d from 1 to 9
                   do (setf (aref prev d) (aref now d))))
    (mod 
     (loop for d from 1 to 9
           sum (satisfied-highest N d prev now))
     *prime*)))

(defun main ()
  (let ((N (read)))
    (princ (satisfied-patterns N))))

#-swank(main)Code language: Lisp (lisp)
5. E – 1111gal password(197ms)

5.1. フリップする

少し効率化を考えました。
prev[0] = prev[10] = 0 に固定すれば、分岐はなくなります。
初期値は、prev[1]〜prev[9] = 1 にセットしておきます。
また、even-now, odd-now を持つことにして、奇数・偶数でフリップして、セットするようにしました。

(defparameter *prime* 998244353)
(defun satisfied-highest/effi (N d odd-now even-now)
  (let* ((now (if (evenp N) even-now odd-now))
         (prev (if (evenp N) odd-now even-now)))
    (setf (aref now d)
          (mod (+ (aref prev (1- d))
                  (aref prev d)
                  (aref prev (1+ d)))
               *prime*))))

;; (satisfied-patterns 4) ; => 203
;; (satisfied-patterns 1000000) ;=> 248860093
(defun satisfied-patterns/effi (N)
  (let ((even-now (make-array 11 :element-type 'fixnum
                            :initial-element 0))
        (odd-now (make-array 11 :element-type 'fixnum
                            :initial-element 0)))
    (loop for d from 1 to 9
          do (setf (aref odd-now d) 1))
    (loop for i from 2 to (1- N)
          do (loop for d from 1 to 9
                   do (satisfied-highest/effi
                       i d odd-now even-now)))
    (mod 
     (loop for d from 1 to 9
           sum (satisfied-highest/effi N d odd-now even-now))
     *prime*)))

(defun main/effi ()
  (let ((N (read)))
    (princ (satisfied-patterns/effi N))))
#-swank(main/effi)Code language: PHP (php)

解答時間は、161 ms まで短縮できました。
ただ、

5.1. フリップする
5.1. フリップする