Closed7
paizaでClojureの勉強 - 【シミュレーション 1】反復横跳び (paizaランク B 相当)
反復横跳びの回数(k)から左を何回通過したかを計算する関数
2回までは0、それ以降は4回やるごとにカウントアップするので、以下のようなコードになる
※ /
だけだとratioになるので、intにキャストする必要がある
(defn count-left-jump [k]
(int (/ (+ k 1) 4)))
テストコード
(deftest count-left-jump-test
(is (= (count-left-jump 0) 0))
(is (= (count-left-jump 1) 0))
(is (= (count-left-jump 2) 0))
(is (= (count-left-jump 3) 1))
(is (= (count-left-jump 4) 1))
(is (= (count-left-jump 5) 1))
(is (= (count-left-jump 6) 1))
(is (= (count-left-jump 7) 2))
(is (= (count-left-jump 8) 2))
(is (= (count-left-jump 9) 2))
(is (= (count-left-jump 10) 2))
(is (= (count-left-jump 11) 3))
(is (= (count-left-jump 12) 3))
(is (= (count-left-jump 13) 3))
(is (= (count-left-jump 14) 3))
(is (= (count-left-jump 15) 4))
(is (= (count-left-jump 16) 4)))
左と中央の間を通過した回数
- ちょうど左の地点にいるとき以外は、左を通過した回数 * 2回通過している
- ちょうど左の地点にいるときは、まだ片道しか通ってないので、左を通過した回数 * 2回 - 1
※ Clojureにおいて、booleanを返す関数名には、慣習的に関数名の末尾に?をつけることが推奨されている
(defn is-just-left-point? [k]
(zero? (mod (+ k 1) 4)))
(defn count-pass-between-left-and-center [k]
(let [count (* (count-left-jump k) 2)]
(if (is-just-left-point? k) (- count 1) count)))
テストコード
(deftest count-pass-between-left-and-center-test
(is (= (count-pass-between-left-and-center 3) 1))
(is (= (count-pass-between-left-and-center 4) 2))
(is (= (count-pass-between-left-and-center 6) 2))
(is (= (count-pass-between-left-and-center 7) 3))
(is (= (count-pass-between-left-and-center 8) 4))
(is (= (count-pass-between-left-and-center 10) 4))
(is (= (count-pass-between-left-and-center 11) 5))
(is (= (count-pass-between-left-and-center 12) 6)))
左と中央の間を通過した回数の合計の移動距離を求める
まず、左と中央の間を通過した、その回数での移動距離を求める
- Nが1の場合
- [0-2] : 0
- [3-4] : 1 * x
- [5-6] : 2 * x
- Nが2の場合
- [0-4] : 0
- [5-8] : 1 * x
- [9-12] : 2 * x
なので以下のようなコード
(defn calc-extra-moved-at [pass-count x n]
(let [divider (* 2 n)
times (- (int (Math/ceil (/ pass-count divider))) 1)]
(* x times)))
テストコード
(deftest calc-extra-moved-at-test
(testing "Given [x n] = [1 1]"
(is (= (calc-extra-moved-at 2 1 1) 0))
(is (= (calc-extra-moved-at 3 1 1) 1))
(is (= (calc-extra-moved-at 4 1 1) 1))
(is (= (calc-extra-moved-at 5 1 1) 2))
(is (= (calc-extra-moved-at 6 1 1) 2))
(is (= (calc-extra-moved-at 7 1 1) 3))
(is (= (calc-extra-moved-at 8 1 1) 3))
(is (= (calc-extra-moved-at 9 1 1) 4)))
(testing "Given [x n] = [3 2]"
(is (= (calc-extra-moved-at 2 3 2) 0))
(is (= (calc-extra-moved-at 4 3 2) 0))
(is (= (calc-extra-moved-at 5 3 2) 3))
(is (= (calc-extra-moved-at 8 3 2) 3))
(is (= (calc-extra-moved-at 9 3 2) 6)))
(testing "Given [x n] = [2 3]"
(is (= (calc-extra-moved-at 6 2 3) 0))
(is (= (calc-extra-moved-at 7 2 3) 2))
(is (= (calc-extra-moved-at 12 2 3) 2))
(is (= (calc-extra-moved-at 13 2 3) 4))))
次に、合計の移動距離を求める
各通過回数時点での、移動距離のリストを作って、そのリストの要素の合計を出す
(defn calc-total-extra-moved [pass-count x n]
(let [extra-moved-list (map #(calc-extra-moved-at (inc %) x n) (range pass-count))]
(reduce + extra-moved-list)))
テストコード
(deftest calc-total-extra-moved-test
(testing "Given [x n] = [3 1]"
(is (= (calc-total-extra-moved 2 3 1) 0))
(is (= (calc-total-extra-moved 3 3 1) 3))
(is (= (calc-total-extra-moved 4 3 1) 6))
(is (= (calc-total-extra-moved 5 3 1) 12)))
(testing "Given [x n] = [3 2]"
(is (= (calc-total-extra-moved 4 5 2) 0))
(is (= (calc-total-extra-moved 5 5 2) 5))
(is (= (calc-total-extra-moved 8 5 2) 20))
(is (= (calc-total-extra-moved 9 5 2) 30))))
問題を勘違いしていた。。4Nの倍数で伸びていくと思ったけど、4Nのときにだけ伸びるだけだった。。
なので、余計に移動した距離を求めるには、以下の計算式
("合計の左と中央の間を通過した回数" - "4N回までに左と中央の間を通過した回数") * 伸ばした距離
コードにすると以下
(defn calc-extra-moved [n x k]
(let [pass-count (count-pass-between-left-and-center k)
pass-count-before-extend (count-pass-between-left-and-center (* n 4))]
(* x (- pass-count pass-count-before-extend))))
テストコード
(deftest calc-extra-moved-test
(is (= (calc-extra-moved 1 3 10) 6))
(is (= (calc-extra-moved 2 5 20) 30)))
コードの全体像
提出コード
(ns clojure-practice.paiza.libs
(:require [clojure.string :as string]))
(defn split-line-by-space [line]
(string/split line #" "))
(defn read-int-values-line []
(vec (map #(Integer/parseInt %) (split-line-by-space (read-line)))))
(defn count-left-jump [k]
(int (/ (+ k 1) 4)))
(defn is-just-left-point? [k]
(zero? (mod (+ k 1) 4)))
(defn count-pass-between-left-and-center [k]
(let [count (* (count-left-jump k) 2)]
(if (is-just-left-point? k) (- count 1) count)))
(defn calc-extra-moved [n x k]
(let [pass-count (count-pass-between-left-and-center k)
pass-count-before-extend (count-pass-between-left-and-center (* n 4))]
(* x (- pass-count pass-count-before-extend))))
(defn main []
(let [[n x k] (read-int-values-line)]
(println (calc-extra-moved n x k))))
(main)
このスクラップは2023/07/06にクローズされました