CTFもメンバーのきっかけで少しカジリましたが、今回はプロコンをカジってみます。 (少し前の話で、記憶を復元しながら書いてます)
なんかかっこ良かったので貼ってみる。
競技プログラミング、プログラミングコンテストと検索して頂ければ。
簡単に言うと、プログラミングして競おう!というお話です。
うちのアンバサダーが主催している勉強会に便乗して、参加しました。
プロコン部、始まりました。
— 株式会社スプーキーズ 👻 (@spookiesjp) 2020年2月28日
うちのメンバーも便乗して、勝手に参加です。 https://t.co/LT2CGriXFn pic.twitter.com/iQCARd13ty
とはいえ、右も左も分からない状態だったので、まずは初心者用の過去問題集を横でやってました。
「PHP なんすね。」みたいな横やりを入れられながら、フンフンと。
当日・翌日で、10問ぐらいやったんですが、面白かったのをご紹介
黒板に N 個の正の整数 A1,...,AN が書かれています. すぬけ君は,黒板に書かれている整数がすべて偶数であるとき,次の操作を行うことができます. 黒板に書かれている整数すべてを,2 で割ったものに置き換える. すぬけ君は最大で何回操作を行うことができるかを求めてください.
問題文は、ざっくりこんな感じ
ほうほう、とりあえずそのまま書いてみようじゃないの
ドーン!
<?php $first = trim(fgets(STDIN)); $second = trim(fgets(STDIN)); $c = intval($first); // 整数の数 $nums = explode(" ", $second); $nums = conv($nums); $cnt = 0; while ($nums) { $cnt++; $nums = conv($nums); } function conv($nums) { $half = array(); for ($i = 0; $i < count($nums); $i++) { $num = intval($nums[$i]); if ($num % 2 == 1) { return false; } $half[] = $num; } return $half; } echo $cnt;
https://atcoder.jp/contests/abs/submissions/10389597
変数名とか、関数名とかは、他の問題の引き続きとかでサボってます(言い訳)
これだと速い場合は 9ms ですが、特定の入力で 2 秒を超えちゃうので、考えを改めよと。
そこで、タイトルをヒントに shift 演算を考えてみることにする。
もはや思考の過程を忘れちゃったので、コメントから復元すると
bit で和演算して、右シフトして 0 の位置を探すことを考えた
ということらしい。
2の累乗の共通因数を、求めてるってことだよね!? > 当時の自分
<?php $first = trim(fgets(STDIN)); $second = trim(fgets(STDIN)); $c = intval($first); // 整数の数 $nums = explode(" ", $second); $or = orBit($nums); $cnt = 0; while ($or > 0) { if (($or % 2) == 1) { break; } $cnt++; $or = $or >> 1; } /* bit で和演算して、右シフトして 0 の位置を探すことを考えた */ function orBit($nums) { $or = $nums[0]; for ($i = 1; $i < count($nums); $i++) { $num = intval($nums[$i]); $or = $or | $num; } return $or; } echo $cnt;
https://atcoder.jp/contests/abs/submissions/10394370
これで、 全入力 10ms に出来ましたー!!!パチパチパチ
この後、感想戦をしていたら、アンバサダーが Rust で単純(最初のやり方)に書いたら 2ms でしたよってサラッと言われて、更に衝撃を受けた。