- AtCoder ABC453のA・B問題をCommon Lispで解きました。
- A問題では文字列の先頭から連続する
oを除去するロジックを自前ループで実装しましたが、string-left-trimを使えばより簡潔に書けます。 - B問題では直前の保存値との差が閾値X以上のときだけ記録する処理を、
loopのwithとwhenを使って実装しています。
1. A – Trimo
長さ の文字列 が与えられます。 のうち先頭に連続する
oをすべて取り除いた文字列を出力してください。なお、 中のすべての文字が
oである場合は空文字列を出力してください。入力は以下の形式で標準入力から与えられる。
N S答えを出力せよ。
A – Trimo
例 1
7 ooparts
oopartsのうち先頭に連続するoをすべて取り除くとpartsとなります。parts
例 2
6 abcooo先頭の文字が
oでない場合もあります。abcooo
1.1. 回答
素直に文字列の先頭が文字に合致する間進むことにしました。
(defun solve (n s)
(declare (type fixnum n)
(type string s)
(ignore n))
(subseq s (length-first-char s #\o)))
(defun length-first-char (str ch)
(declare (type string str)
(type character ch))
(loop for i from 0
for ch2 across str
while (eql ch2 ch)
finally (return i)))
(defun main ()
(let* ((n (read))
(s (read-line)))
(princ (solve n s))))
#-swank
(main)Code language: Lisp (lisp)

ただ、Common Lispには、string-left-trim があるので、実はそのまま解決します。
2. B – Sensor Data Logging
ある測定では、時刻 におけるセンサーの測定値を以下の規則で記録します。
- 時刻 では、測定値を保存する。
- 時刻 では、「現時刻の測定値」と「直前に保存された測定値」との差の絶対値が 以上であるとき、またその時に限り値を保存する。
時刻 におけるセンサーの測定値は でした。
測定値が保存された時刻と保存された値とを、時刻の昇順に出力してください。
入力は以下の形式で標準入力から与えられる。
測定値が 回保存され、そのうち時刻の昇順に並べた時に 回目の時刻が 、測定値が であったとき、以下の形式で出力せよ。
B – Sensor Data Logging
2.1. 回答
a – prev の絶対値 が X のときだけ計測するので、prevを更新しながら、値のペアを集めることにしました。
(defun measure (X As)
(declare (type fixnum X)
(type list As))
(loop for a in As
for time from 0
with prev = (car As)
when (or (= time 0)
(>= (abs (- a prev)) X))
collect (list time (setf prev a))))Code language: Lisp (lisp)
あとは、入出力を整えて完成です。
Anの個数は Tn + 1 なので、そこだけ注意が必要でした。
(defun print-measured (Mn)
(loop for m in Mn
do (format t "~d ~d~%" (car m) (cadr m))))
(defun main ()
(let* ((Tn (read))
(X (read))
(An (loop for i from 0 to Tn
collect (read)))
(Mn (measure X An)))
(print-measured Mn)))
#-swank
(main)Code language: Lisp (lisp)