AtCoder ABC181 に参加してきた

atcoder.jp

今回は A, B, C, D まで解けた。目標のD問題まで解けたのでとりあえずよし・・・?

パフォーマンス1000超えるかなって思ったけど、超えなかったのでそこは残念。

A - Heavy Rotation

偶奇見るだけ。

A問題はうっかりでWA出しそうで怖い。。

defmodule Main do
  def read_single() do
    IO.read(:line) |> String.trim() |> String.to_integer()
  end
 
  def main() do
    case rem(read_single(), 2) do
      0 -> "White"
      1 -> "Black"
    end
    |> IO.puts()
 
  end
 
end

B Trapezoid Sum

elixirには a..b |> Enum.sum() という便利関数があるので、それ使うだけ。

defmodule TrapezoidSum.Main do

  def read_single() do
    IO.read(:line) |> String.trim() |> String.to_integer()
  end

  def main() do

    _ = read_single()

    IO.binstream(:stdio, :line)
    |> Stream.map(&String.trim/1)
    |> Stream.map(&(String.split(&1, " ") |> Enum.map(fn i -> String.to_integer(i) end)))
    |> Stream.map(fn [a, b] -> Enum.sum(a..b) end)
    |> Enum.to_list()
    |> Enum.sum()
    |> IO.puts()
  end

end

C Collinearity

適当な3点を選んで傾き見るだけ。解説の0除算を避ける方法はなるほどと思った。

      a =  (y2 - y1) * (x3 - x1)
      b =  (y3 - y1) * (x2 - x1)
      if a == b  do

こんな感じになるのかな。覚えておこう。

defmodule Collinearity.Main do
  def read_single() do
    IO.read(:line) |> String.trim() |> String.to_integer()
  end

  def read_multi_array() do
    IO.read(:all)
    |> String.split("\n")
    |> Enum.filter(fn s -> String.length(s) > 0 end)
    |> Enum.map(&(String.split(&1, " ") |> Enum.map(fn i -> String.to_integer(i) end)))
  end

  def combination(_, 0), do: [[]]
  def combination([], _), do: []

  def combination([x | xs], n) do
    for(y <- combination(xs, n - 1), do: [x | y]) ++ combination(xs, n)
  end

  def main() do
    _n = read_single()

    xys = read_multi_array()

    combination(xys, 3)
    |> Enum.reduce_while("No", fn [[x1, y1], [x2, y2], [x3, y3]],_ ->
      a = if x1 != x2, do: (y2 - y1) / (x2 - x1), else: :inf
      b = if x1 != x3, do: (y3 - y1) / (x3 - x1), else: :inf
      if a == b  do
        {:halt, "Yes"}
      else
        {:cont, "No"}
      end
    end)
    |> IO.puts()
  end

end

D Hachi

8の倍数になる条件は下3桁が8の倍数かどうからしい。 与えられた数字列の各数字について min(出現回数, 3) だけ複製した配列を作って、全探索した。 最大でも 27個しか要素がないので、 3つずつの全探索しても余裕ですね。

入力が2桁以下の場合の考慮を忘れてWA出してしまったのがもったいなかった。。。

defmodule Hachi.Main do
  def permutation(_, 0), do: [[]]

  def permutation(list, n) do
    for x <- list, rest <- permutation(list -- [x], n - 1), do: [x | rest]
  end

  def main() do

    s =
      IO.read(:line)
      |> String.trim()
      |> String.split("")
      |> Enum.filter(&(String.length(&1) > 0))
      |> Enum.map(&String.to_integer/1)
      |> Enum.frequencies
      |> Map.to_list()
      |> Enum.map(fn {i, c} ->
        count = min(3, c)
        for _ <- 1..count, do: i
      end)
      |> List.flatten()

    s
    |> permutation(min(3, length(s)))
    |> Enum.reduce_while("No", fn a, _ ->
      cond do
        Integer.undigits(a) |> rem(8) == 0 -> {:halt, "Yes"}
        true -> {:cont, "No"}
      end
    end)
    |> IO.puts()

  end

end

AtCoder ARC107 に参加してきた

atcoder.jp

今回はA, B 問題をなんとかクリア。

A - Simple Math

A, B, C の総和を求めてから掛ければいいのかなって思ったら通った。

    a = 1..a |> Enum.sum() |> rem(@mod)
    b = 1..b |> Enum.sum() |> rem(@mod)
    c = 1..c |> Enum.sum() |> rem(@mod)
 
    ans = rem(a * b, @mod)
    ans = rem(ans * c, @mod)
    ans |> IO.puts()

余りをとる系はいまいちどこでとればいいのかまだよくわからない。。。

B - Quadruple

a+b−c−d=K のままだと変数が4つあってつらいので、まずは変数2つで考えることにした。

A - C = K

このとき K については 絶対値 で考えてもいいはず。 (Kがマイナスのときは C - A = K と同じだから)

このとき A > C > 0 なので、 A について K+2..2N の範囲で見ていけば、 C = A - K でCも決定できる。

あとはA, C それぞれについて変数2つ使った組み合わせを考える。
整数xになる変数2つ使った組み合わせは0を含まないので、 n - 1 通りになる

参考: 【応用】指定した合計値になる整数の組合せ

今回は更に使える数が n までになるので、xとnの差の組み合わせを引いてあげればOK

  def main() do
    [n, k] = read_array()
    k = abs(k)
    (for a <- (2 * n)..(k + 2), do: p(a, n) * p(a - k, n))
    |> Enum.sum()
    |> IO.inspect()

  end

  def p(n, k) do
    s = (n - k - 1)
    s = if s > 0, do: s, else: 0
    (n - 1) - (s * 2)
  end

ISUCON10にElixirで参戦して、惨敗してきました。

9/12(土)に行われたISUCON10にぼっち参戦してきました。

以前から気になってはいたものの、参加できていなかったので、ようやく初参戦することができました!

 

結果は・・・

 

はい、スコア0でフィニッシュでした 😇

 

なぜElixir?

f:id:tamanugi:20200914234205p:plain

(微妙に名前隠れてないけど、本名じゃないしまぁいいってことで)
 

純粋にElixirをもうちょっと使えるようになりたいなって思っていたり、社内Slackの#isuconでこんな冗談を言っていたりして、あとに引けなくなったとかそんな感じです。
(Elixirエンジニアに転職したいという思いもあったり)

過去のISUCONでもフルスクラッチ参戦した方がいたみたいなので、まぁ可能性は0じゃないかと思いチャレンジしてみました。

 

やったこととか

リポジトリはこちらになります。

github.com

 

ElixirのWEBフレームワークといえば、Phoenixですが、ISUCON向きではないなと思い、Plug+Cowboy+Ectoといった構成でチャレンジしました。

他の参照実装でも大体薄いWEBフレームワークの実装なので、それに合わせたような形ですね。

一応実装 5時間 + チューニング3時間で考えていたのですが、結局実装が終わらずでした・・・😭

完全にスキル不足ですね。。。

 

はまったこと

SQLの実行結果を構造体に入れる方法

Rubyの参照実装を参考に実装していて、とりあえずSQL直書きでいいかと思っていたのですが、その実行結果を構造体に変換する方法がわかりませんでした。

終わってから調べてみたところ、Ecto.Repo.load/2 を使えばできるみたいでした。

 

レスポンスが不正です

スコアが0になったのは、ベンチマークのアプリケーションの妥当性チェックを通すことができなかったからです。。。

ローカルで開発して、curlで叩いて目視で確認していました。なので、上で書いたような構造体にしてからJSONに変換していなかったせいで、ぱっと見それっぽいレスポンスが返ってきているように見えても、フィールド名が違った、構造が違った・・・ということがほとんどのAPIで発生してしまっていました。

しかもベンチマークのエラーメッセージでは細かいエラーが確認できないため(当たり前ですが)、何が違うのかを把握するのに時間がかかってしまいました。。。

Plugのテストは簡単にかけるので、ざっくりとレスポンスの型があっているかだけでもテスト書けばよかったなと思います。

ファイルのアップロード方法がわからなかった

もうこれは問題外なレベルで恥ずかしいのですが、Plugでmultipart-formを受け取る方法がわかりませんでした😇

plug Plug.Parsers,
  parsers: [:urlencoded, :multipart, :json],

みたいな感じで、:multipart を追加するんだろうなと思いますが、ちゃんと試してみようと思います。

だいぶ終盤だったので、ここの実装は諦めて isuumo.go.service を立ち上げて、Nginx 設定追加してそちらに流すようにしました。
(もはやISUCONとは。。。)

EctoのNo Database Selected 

アプリケーションの妥当性チェックの段階でそこまでクエリを実行していないはずですが、Ecto経由で実行したクエリは No Database Selected のエラーで失敗するという事象に悩まされました。

Too Many Connections とかのエラーならまだわかるのですが、No Database Selectedのエラーで失敗するというのがわからず。。。(同じAPI/箇所で失敗するのではなく、いろんなとこで1,2回だけ失敗する)

pool_sizeの指定がわるいのかと思い、適当に変えてみたけど変わらずでした。。。

これがなければ(一部はgoに流していたものの)妥当性チェックを抜けれていたと思うのでとても悔しかったです。

 

その他

久しぶりに .ssh/config をいじりました。 ProxyJump といった項目が初見でしたが、比較的最近のOpenSSHで追加されたんでしょうか?

ポートフォワーディングは以下のように .ssh/config に追加して、 ssh isucon-web するだけで行けるようにしていました。

Host isucon-web
ProxyJump isucon-bastion
User isucon
HostName xxx.xxx.xxx.101
LocalForward 8080 xxx.xxx.xxx.101:80

 

感想

結果こんな形で参加枠を潰してしまいごめんなさい!って気持ちになりましたが、競技中はめちゃくちゃ集中して取り組むことが出来て、凄い楽しかったです。

また感想戦も交われない寂しさと悔しさも強かったですが、それ以上にとても色々と勉強になりました。SPATIAL INDEXとかは知らかなったし、その他色々よく気づくな〜ってポイントが多く尊敬の念でいっぱいでした。

来年こそはちゃんと修行して、Elixirで予選突破したいと思います!

 

最後に運営のみなさま、とても素晴らしいイベントに参加させていただきまして、本当にありがとうございました!

 

PS. 決勝進出した弊社つよつよエンジニア3人組頑張ってください〜〜 💪

【ふくもく会】開発環境自慢LTで「ゆるかわフォントいいよって話」というLTしてきた

先日、ふくもく会で開発環境をテーマにしたLT大会があったので、

「フォント」をテーマにしたLTをしてきた。

 

speakerdeck.com

 

社内ではLTしたことはあったが

こういった外部の勉強会では初めてだったので。

割りと緊張した。

 

結構早口になってしまい、時間もあまったので

次回LTのときはもうすこしゆっくり話すようにしたい。。。

 

 

今回は kanazawa.rb さんとのコラボで、

向こうの人のLTも聞けたのでよかった。

 

vimで :up とか ZZ とか :x 初めて知った。

 

fukumoku.connpass.com

 

Vimを少し始めてみる

エディタはAtomを使っていましたが、

重いのと不安定なのがずっと不満でふとVimを使ってみようと思いたった

 

...とはいえ、一からvimrcを育てていくのはつらいので

Githubでvimrcで検索して一番スターが多かった以下の

リポジトリのvimrcを使わせてもらうことに

 

github.com

 

The Ultimate vimrc  !!!!!!

 

プラグインとかいっぱい?でよくわからないけど

これをベースに自分で色々と改良していきたいなー

 

とりあえず leaderをスペースに変更

 

さぁ Let's Vim Life!!

(なお以前はEmacsを3日で飽きた模様)