40代文系社内SEが、AtCoder Beginner Contest 161 D - Lunlun NumberをCommon Lispで解いてみました。
問題文には特に難しいことは書いていません。
簡単に思いつく解き方としては、1から順番にルンルン数かどうかを判定していく方法があります。
しかし、入力例4で$K$が最大のときに$10^9$を超えるので間に合いません。他の解き方を考えます。
入力例1のルンルン数を眺めていると、親子関係があることに気が付きました。親が$1$、個が$10$と$11$、孫が$100$、$101$、$110$、$111$、$112$ということです。
親を元に子のルンルン数を追加する計算量は$O(1)$なので、間に合います。
(let* ((k (read))
(lunlun (make-array (1+ k))))
;; ルンルン数の1~9を埋める
(loop for i from 1 to (min k 9)
do (setf (aref lunlun i) i))
(when (> k 9)
;; ルンルン数の10~Kを埋める
(loop with parent = 1
with child = 10
while (<= child k)
for lunlun-parent = (aref lunlun parent)
for lunlun-parent-1 = (mod lunlun-parent 10)
do (when (> lunlun-parent-1 0)
;; 親ルンルン数の1桁目が0より大きいとき
(setf (aref lunlun child) (+ (* lunlun-parent 10)
(1- lunlun-parent-1)))
(incf child))
(when (<= child k)
(setf (aref lunlun child) (+ (* lunlun-parent 10)
lunlun-parent-1))
(incf child))
(when (and (< lunlun-parent-1 9)
(<= child k))
;; 親ルンルン数の1桁目が9より小さいとき
(setf (aref lunlun child) (+ (* lunlun-parent 10)
(1+ lunlun-parent-1)))
(incf child))
;; 次の親ルンルン数に進む
(incf parent)))
(format t "~A~%" (aref lunlun k)))

