AtCoder Beginner Contest 117の解説
A - Entrance Examination
入力:
出力: 世界Aで実際に進んでいる時間(絶対誤差と相対誤差は以下である必要がある)
制約:
サンプルでエスパーしましょう(は?)
writefln("%.6f", T / X);
感想: エスパー
B - Polygon
入力:
出力: 角形が描けるなら'Yes'、そうでないなら'No'
制約:
問題文に定理が書かれているので、これを参考にして実装します。
具体的には、の総和をとり、一番長い辺の長さをそこから引いたものが、一番長い辺より真に大きいなら'Yes'、そうでないなら'No'と出力すればよいです。
if(L.reduce!max < L.sum - L.reduce!max) { writeln("Yes"); } else writeln("No");
感想: 定理が書かれてなかったら、めっちゃ点数上がってそうな気がした。
C - Streamline
入力:
出力: 目的を達成するまでに移動を行う回数の最小値
制約:
移動と言っているので、まずXをソートし、についてな数列を考えたくなります。
のときは、個のコマによって個の座標に訪れてしまうことが可能なので、この場合は0と出力すればよいです。
そうでないときは、1個以上のコマを移動する必要があります。
このとき、考えた数列について、大きい順から要素の総和をとり、の最大値と最小値の差からその総和を引けば、求める操作回数がわかります。
X.sort(); auto arr = new int[](M-1); foreach(i; 0..M-1) arr[i] = abs(X[i+1] - X[i]); //X.writeln; //arr.writeln; arr.sort!"a > b"(); long tmp; if(N >= M) { writeln(0); return; } foreach(i; arr[0..N-1]) { tmp += i; } //tmp.writeln; writeln(abs(X.reduce!max - X.reduce!min) - tmp);
感想: こういう問題、入力例から何となく解法を考えるのが大事な気がする
D - XXOR
入力:
出力: の最大値
制約:
公式解説を読めばわかりますが、難しいので、1から理解した自分が書いてみます。
まず、これは質問ですが、とはどちらが大きいでしょうか?
当然ですが、あなたはどのようにして大小を比較したでしょうか。
きっと、5桁目がだからすぐにわかったのだろうと思います。
では、とは、どちらが大きいでしょうか?
これはですね。5桁目はどちらもなのでまだ大小が確定していませんが、4桁目を見るとより大小が確定します。公式解説では、このことを小難しい書きかたで表わしています。(雰囲気はこんな感じなはず)
この問題では、なるについてとしています。
なので、この条件を満たしている状態を考えて、の値を考えてみます。
のとき、特に何も考えずを求めてみるとよいです。
そうでないとき、Kの2進法表記を考えてみます。
が確定するのは、XとKの二進法表記を上から見ていって、あるところでとなるときです。
そのため、Kの二進法表記でそこがであるとき、そこをXの二進法表記でとすることを考えます。そこの桁を桁目とします。
このとき、Xはより上の桁はKと等しく、より下の桁は貪欲に選ぶことができます。
したがって、下のようなコードを書くことになります。なお、は桁目がであるの要素の個数を表わしています。
auto c = new ulong[](64); foreach(v; A) foreach(i; v.bitsSet) c[i]++; ulong res; if(K == 0) { writeln(A.sum); return; } // X < K のとき foreach(i; 0..K.log2.ceil.to!ulong) { // Kの二進法表記でi桁目が1でなければcontinue(X < Kにしたいので) if(!(K & (1UL << i))) continue; ulong X = K; X &= ~(1UL << i); // Xのi桁目を0にする(i桁目でX < Kを確定させたいので) foreach(j; 0..i) { if(c[j] > N-c[j]) { // その桁を1にしてxorしたほうが都合がよいのか X &= ~(1UL << j); } else X |= (1UL << j); } ulong tmp; foreach(v; A) { tmp += v ^ X; } res = max(res, tmp); } ulong tmp; foreach(v; A) { // X = K のとき tmp += v ^ K; } res = max(res, tmp); res.writeln;
感想: これを理解したつもりでコードを書くと、X = Kの場合を忘れていてWAを連発したりした。
本番では嘘解法(上から貪欲に決めるとAC)が通るようになっていたのだが、シフト演算に慣れていないせいで1 << aと書いてしまい、1UL << aと書けばパフォ1600だったのに俺は何をオーバーフローさせてんだ…いやでもこれ嘘だしなあ…という微妙な気持ちになった。(どちらかというとレート上昇を逃したのが悔しい)
後日、しっかり本当の解法を理解しようと努めることによって、桁を上から見ることについて少しはわかったのではないかと思う(桁DPで解く方法についても今後考えたい)
A: Submission #4152674 - AtCoder Beginner Contest 117
B: Submission #4153387 - AtCoder Beginner Contest 117
C: Submission #4158140 - AtCoder Beginner Contest 117
D: Submission #4184409 - AtCoder Beginner Contest 117
D(別解法): Submission #4183962 - AtCoder Beginner Contest 117
D(嘘解法): Submission #4167642 - AtCoder Beginner Contest 117