2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

闘魂Elixir ーー AtCoder Beginner Contest 350をElixirで楽しむ

Last updated at Posted at 2024-04-26

$\huge{元氣ですかーーーーッ!!!}$
$\huge{元氣があればなんでもできる!}$

$\huge{闘魂とは己に打ち克つこと。}$
$\huge{そして闘いを通じて己の魂を磨いていく}$
$\huge{ことだと思います}$

はじめに

AtCoder Beginner Contest 350Elixirで解いてみます。

AtCoderを解くのが趣味で、休憩時間に解いているという若い人がいて、それってすごい意識の高い休憩時間の過ごし方だと思って、私も真似してみることにしました。

私達ハウインターナショナルでは、社名をもじってハウッカソンという名のイベントを毎月最終金曜日に実施しています。

HAW + Hackathon = Hawckathon!!

ハウッカソンのテーマに競技プログラミングを選ぶメンバーもいます。

AtCoderをElixirでやってみる

入力の読み取り方や解答の作り方は、別の記事にまとめています。

ご参照くださいませ。

ElixirAtCoderを楽しむためには、エントリポイントをMain.main/0にする必要があります。つまりMainモジュールを作って、その中にmain/0関数を定義するわけです。

A - Past ABCs

問題はリンク先をご参照くださいませ。
私の解答を貼っておきます。

私の解答

問題文を読んでいることを前提にひとこと解説をしておきます。

入力値"ABCNNN"(Nは数字)から"NNN"を取り出して、文字列から整数に変換してあげればよさそうです。
パターンマッチでNNNを取り出せます。"ABC" <> num = ...が該当します。

"000"も入力にはあり得えるようです。Runさせてみて、 WA (Wrong Answer) がでて気づきました。
第316回はNo判定にする必要があります。
以上を踏まえると、変換後の整数をXとしたとき、1 < X <= 315 or 317 <= X < 350のときにYesそれ以外はNoです。

ifは使わずにパターンマッチでスッキリと書けます。

defmodule Main do
  def main do
    "ABC" <> num = IO.read(:line) |> String.trim()
    
    num
    |> String.to_integer()
    |> solve()
    |> IO.puts()
  end
  
  def solve(316), do: "No"
  def solve(0), do: "No"
  def solve(num) when num < 350, do: "Yes"
  def solve(_num), do: "No"
end

B - Dentist Aoki

問題はリンク先をご参照くださいませ。
私の解答を貼っておきます。

私の解答

問題文を読んでいることを前提にひとこと解説をしておきます。

数字が偶数回でてくると歯は生えています。数字が奇数回だと歯がなくなっています。
それに気づけば、数字の出現回数を調べて、奇数回の数字の個数をNから引いてあげると、生えている歯の本数を求めることができます。
リストの中に含まれる要素の出現回数といえば、 Enum.frequencies/1を使えばよいでしょう。

defmodule Main do
  def main do
    [n, _q] =
      IO.read(:line) |> String.trim() |> String.split(" ") |> Enum.map(&String.to_integer/1)
    ts =
      IO.read(:line) |> String.trim() |> String.split(" ") |> Enum.map(&String.to_integer/1)
    
    solve(ts, n)
    |> IO.puts()
  end
  
  def solve(list, n) do
    list
    |> Enum.frequencies()
    |> Map.values()
    |> Enum.filter(& rem(&1, 2) == 1)
    |> Enum.count()
    |> Kernel.-()
    |> Kernel.+(n)
  end
end

C - Sort

問題はリンク先をご参照くださいませ。
私の解答を貼っておきます。

私の解答

問題文を読んでいることを前提にひとこと解説をしておきます。

苦労しました。Elixirだと、 「TLE (Time Limit Exceeded): 問題で指定された実行時間以内にプログラムが終了しませんでした。」が出そうな問題です。

以下2点の改善でなんとか 「TLE (Time Limit Exceeded)」を克服できました。

  • indexes |> Enum.zip(list) |> Map.new()Enum.zip/2ではなく、Enum.with_index/2を使うようにした点
  • 結果の格納をListではなく、:etsというインメモリストアに保存するようにした点

これでギリギリ2秒以内に終わるようになりました。

defmodule Main do
  def main do
    n = IO.read(:line) |> String.trim() |> String.to_integer()
    list =
      IO.read(:line) |> String.trim() |> String.split(" ") |> Enum.map(&String.to_integer/1)
    
    indexes = 0..(n - 1)
    index_map = list |> Enum.with_index(fn element, index -> {index, element} end) |> Map.new()
    value_map = list |> Enum.with_index() |> Map.new()

    db = :ets.new(:example_db, [:ordered_set, :named_table])

    solve(indexes, index_map, value_map, db)
    |> IO.puts()
  end

  def solve(indexes, index_map, value_map, db) do
    indexes
    |> Enum.reduce({index_map, value_map, 0}, fn i, {acc_index_map, acc_value_map, cnt} ->
      value = acc_index_map[i]
      expected_value = i + 1
      if value == expected_value do
        {acc_index_map, acc_value_map, cnt}
      else
        index = acc_value_map[expected_value]
        new_acc_index_map = %{acc_index_map | i => expected_value, index => value}
        new_acc_value_map = %{acc_value_map | expected_value => i, value => index}

        :ets.insert(db, [{cnt, "#{expected_value} #{value}"}])
        new_cnt = cnt + 1
        {new_acc_index_map, new_acc_value_map, new_cnt}
      end
    end)
    |> elem(2)
    |> format()
  end

  defp format(0), do: "0"

  defp format(k) do
    str_operations = ((k - 1)..0)
    |> Enum.reduce("", fn i, acc ->
      [{_, operation}] = :ets.lookup(:example_db, i)

      "#{acc}\n#{operation}"
    end)
    
    "#{k}#{str_operations}"
  end
end

参考記事


さいごに

AtCoder Beginner Contest 350Elixirで解くことを楽しみました。
C問題まで解きました。

あなたのお好きなプログラミング言語でお楽しみください。


闘魂とは、 「己に打ち克つこと。そして闘いを通じて己の魂を磨いていくことである」 との猪木さんの言葉をそのまま胸に刻み込んでいます。
知っているだけで終わらせることなく、実行する、断行する、一歩を踏み出すことを自らの行動で示していきたいとおもいます。
アントニオ猪木さんのメッセージから元氣をもらったものとして、それを次代に語り継ぎ、自分自身が「闘魂」を体現するものでありたいとおもいます。


$\huge{元氣ですかーーーーッ!!!}$
$\huge{元氣があればなんでもできる!}$
$\huge{1、2、3 ぁっダァー!}$

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?