これに続いて、Elixir 超初心者が AtCoder に挑戦してみました。
御指導よろしくお願いします。
A問題: Last Letter
defmodule Main do
def main do
IO.read(:line)
IO.read(:line) |> String.trim()
|> String.at(-1)
|> IO.puts()
end
end
与えられた文字列の最後の文字を取り出すということで、String.at(str, -1)
でいいのですね。負数のインデックスが後ろからの指定になるのは、Ruby と同じです。
B問題: Go Straight and Turn Right
defmodule Main do
def main do
IO.read(:line)
IO.read(:line) |> String.trim()
|> solve()
|> IO.puts()
end
defp solve(str) do
str
|> String.codepoints()
|> Enum.reduce({0, {0, 0}}, &doit/2)
|> output()
end
defp doit("S", {0, {x, y}}), do: {0, {x + 1, y}}
defp doit("S", {1, {x, y}}), do: {1, {x, y - 1}}
defp doit("S", {2, {x, y}}), do: {2, {x - 1, y}}
defp doit("S", {3, {x, y}}), do: {3, {x, y + 1}}
defp doit("R", {dir, tpl}), do: {rem(dir + 1, 4), tpl}
defp output({_, {x, y}}), do: "#{x} #{y}"
end
0, 1, 2, 3 の数字で「右下左上」の方向を表しています。右回転なので 1 を足していけば回転します。
C問題: Yamanote Line Game
defmodule Main do
def main do
IO.read(:line) |> String.trim() |> String.to_integer()
|> solve()
end
defp solve(n), do: Enum.to_list(1..2 * n + 1) |> doit()
defp doit([x | xs]) do
IO.puts(x)
IO.read(:line) |> String.trim() |> String.to_integer()
|> doit(xs)
end
defp doit(0, list), do: nil
defp doit(i, list), do: List.delete(list, i) |> doit()
end
まさかのインタラクティブ問題。手続き型言語なら無限ループさせておいて終了条件がきたらループを出ればいいだけですが、関数型言語なので工夫が要りました。再帰でやっています。それから、問題にある標準出力のflush
はどうすればよいかよくわかりませんでしたが、ここではテキトーにIO.puts/1
でよかったようです。
D問題: Swap Hats
defmodule Main do
def main do
s = IO.read(:line) |> String.trim()
t = IO.read(:line) |> String.trim()
solve(s, t) |> IO.puts()
end
defp solve(s, t), do: judge(s) * judge(t) |> output()
defp judge("R G B"), do: 1
defp judge("G B R"), do: 1
defp judge("B R G"), do: 1
defp judge(_), do: -1
defp output(1), do: "Yes"
defp output(-1), do: "No"
end
これは対称群の知識があるとよいです。"R G B"
からの偶置換を1
、奇置換を-1
として、s
t
それぞれについての値の積が1
(偶置換)になればよいというのを実装しました。
最後に
Elixir で AtCoder をやる人が少なくて、参考にしたくてもなかなか…。それから、僕の実装が悪いのかも知れませんが、速度的にもきびしいです。コードの改善など、きびしい指摘を待っております。