AtCoder Beginner Contest 275 備忘録
コンテストページ:AtCoder Beginner Contest 275 - AtCoder
コンテスト中AC:A,B,D
コンテスト後AC:E,F(自力)
Cでハマったのと、Eで回数制限があることを忘れて考察してしまいました。
C - Counting Squares
- 点が、正方形の頂点を半時計回りに順番に並べた点である
これが成立するには以下の条件を満たす 必要があります。
- 辺の長さが等しい
- 凸多角形
- 辺のなす角が全て90°
これは、の全てについて、ベクトル
が以下の3つを満たすことと同値です。
2は外積()、3は内積()です。
1、3は正方形なので自明かと思います。2は1本目の辺と2本目の辺の位置関係が半時計回りである必要があるということです。
2は要らなくて3だけでよいのではと思ってしまいますが、内積だけだと時計回りの角度が半時計回りの角度がわからないので必要になります。
全ての点のあり得る4つの組に全てについて、上の条件を満たすものをカウントすると、同じ正方形が4回数えられるので、条件を満たす個数を1/4したのが答えとなります。
コンテスト中は3の条件が必要だと思っておらず、解けませんでした。
提出コード:Submission #36108492 - AtCoder Beginner Contest 275
D - Yet Another Recursive Function
メモ化再帰の問題。種類数の見積もり方法がわからずにとりあえず通しました。見積もり方法は公式解説参照。
提出コード:Submission #36064977 - AtCoder Beginner Contest 275
E - Sugoroku 4
操作回数を考慮しない点で異なりますが、期待値DPと同じような考え方ができます。
の例で考えてみます。
まず、DPを以下のようにしてみます。
:=マスからゴールできる確率
例えば、なら、
という風に計算できます。
なので、後ろから順に更新できそうと思ってしまいますが、今回はを超える場合には戻ってくるので、例えばの場合、
となり計算できません。
問題文をよく読むと操作回数に限度があります。操作を1回すると残りの操作回数が1減るので、残りの操作回数が0となってしまえばそれ以上の操作はできず、確率が確定します。
そこで、DPに操作回数の情報を持たせ、以下のように変更します。
:=残りの操作回数が回で、マスからゴールできる確率
初期値は、
- について、
- について、
と、設定します(その他もすべて0で初期化します) 。
テーブルの更新はメモ化再帰でもいけそうですが、実装では普通のループにしました。
操作回数の順に、マスについて、
と更新します。
なお、の場合には戻るようにする必要があります。
答えはの値です。
計算量はです。これでも通りましたが、和を求める部分は区間和となっているので、累積和を使えば、に落とせそうです。
提出コード:Submission #36076090 - AtCoder Beginner Contest 275
F - Erase Subarrays
部分和DPを応用します。今回DPテーブルには操作回数の最小値を記録します。
普通の部分和DPのように考えると、
:=の番目までの要素まででできる部分列の和がであるときの操作回数の最小値
となりますが、このままだと操作回数の最小値は求められないので、どうするかを考えます。
例えば、で番目の要素で部分列を作ったとします。番目を選んだら1、選ばなかったら0とした数列を考えます。
となり、この時の操作回数の最小値は、閉区間に操作したときの 4回です。
実は、最初の0を除いてとなる数をカウントすれば最小の操作回数に一致します。最初の0のみ、例外として+1しておきます。
以上より、番目の要素を部分列として選んだ状態と選んでいない状態の2つをDPの情報として追加すれば良いです。すなわち、
:=の番目までの要素まででできる部分列の和がであり、かつ状態がの時の操作回数の最小値
但し、で、なら番目を選んでおり、なら選んでいないことを表す。
初期値は、
とし、他はにしておきます。
遷移については実装を見てもらう方が早いと思います。
ポイントとしては、番目がの状態から番目がの状態に遷移する時に操作回数に+1します。
なお、3次元配列をという感じで領域を確保すると、の場合に配列外参照となるので注意が必要です。
提出コード:Submission #36130326 - AtCoder Beginner Contest 275