AtCoder ABC181 に参加してきた
今回は 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 に参加してきた
今回は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にぼっち参戦してきました。
以前から気になってはいたものの、参加できていなかったので、ようやく初参戦することができました!
結果は・・・
Ectoが整合性チェックですら耐えきれず、スコア付かず!残念だけど楽しかった! #isucon
— たまぬぎ (@tamanugi) 2020年9月12日
はい、スコア0でフィニッシュでした 😇
なぜElixir?
(微妙に名前隠れてないけど、本名じゃないしまぁいいってことで)
純粋にElixirをもうちょっと使えるようになりたいなって思っていたり、社内Slackの#isuconでこんな冗談を言っていたりして、あとに引けなくなったとかそんな感じです。
(Elixirエンジニアに転職したいという思いもあったり)
過去のISUCONでもフルスクラッチ参戦した方がいたみたいなので、まぁ可能性は0じゃないかと思いチャレンジしてみました。
やったこととか
リポジトリはこちらになります。
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をしてきた。
社内ではLTしたことはあったが
こういった外部の勉強会では初めてだったので。
割りと緊張した。
結構早口になってしまい、時間もあまったので
次回LTのときはもうすこしゆっくり話すようにしたい。。。
今回は kanazawa.rb さんとのコラボで、
向こうの人のLTも聞けたのでよかった。
vimで :up とか ZZ とか :x 初めて知った。