Quantcast
Channel: プログラミング
Viewing all articles
Browse latest Browse all 8866

ABC369挑戦記(D問題まで) - JunKobayashi’s diary

$
0
0

4完には成功したものの、C++のnext_permutationによる全探索の構造を書き間違えたせいで時間内の5完には至らず・・・。できれば今回はE問題も解き切りたかった😥😥😥

(個人的復習用:以下の記事で既にまとめているのでnext_permutationによる全探索の書き方を確認せよ)

ABC363挑戦記

追記:再考したところ、各クエリにおいて、\(K\)本の橋を渡る向きをbit全探索するところまで考えが及ばなかったため上記事項だけが固まっていても結局本番中の5完は無理と結論づいた。もっと正確に計算量を見積もり、比較的重たい実装になっても間に合うことを見抜く訓練が必要となる。

※本記事は0-indexedを前提として記載。

 

<A問題>

↓問題のページ↓

A - 369

 

これA問題ってマジすか・・・? 「間違えてB問題をクリックしたか?」と本気で勘違いするには十分すぎるくらいにA問題にしては難易度が高いと感じる。それはそうとして解法を示す。3つの整数\(A,B,x\)の並べ方は以下の6通りである。\begin{equation} A, B, x \tag{1} \end{equation}\begin{equation} B, A, x \tag{2} \end{equation}\begin{equation} A,  x, B \tag{3} \end{equation}\begin{equation}  B, x, A \tag{4} \end{equation}\begin{equation} x, A, B \tag{5} \end{equation}\begin{equation} x, B, A\tag{6} \end{equation}それぞれについて数列の公差\(d\)を求めると、(1)または(5)の場合は\(d = B - A\)であり、(2)または(6)の場合は\(d = A - B\)である。(3)および(4)については、\(x\)が整数でなければならないため\(A, B\)の差が偶数である場合のみ考えることとなる。その場合において、(3)ならば\(\displaystyle{  d = \frac{B - A}{2}}\)であり、(4)ならば\(\displaystyle{  d = \frac{A - B}{2}}\)である。\(d\)を求められれば、\(x\)の値を以下のどちらかで求めればよい。

  • \(x\)の直前にいる値に\(d\)を足す
  • \(x\)の直後にいる値から\(d\)を引く

ここまでできれば、求められた6通りの値を集合型に突っ込んでそのsizeを取るなどしてAC獲得。

 

<B問題>

↓問題のページ↓

B - Piano 3

 

鍵盤の数は\(100\)であるため、両手の初期配置は全部で\(100^2\)通りある。手の移動回数\(N\)は最大で\(100\)であるから、全ての探索範囲は\(100^2 \times 100 = 10^6\)に収まっているので、愚直に全探索をするだけでAC獲得。

 

<C問題>

↓問題のページ↓

C - Count Arithmetic Subarrays

 

\begin{equation} A_i, A_{i + 1}, \dotsc , A_{j - 1}, A_{j} \end{equation}が等差数列である時、\(i \le l \le r \le j\)なる\(l,r\)を任意に選んで得られる\begin{equation} A_l, A_{l + 1}, \dotsc , A_{r - 1}, A_{r} \end{equation}も同じ公差の等差数列になっていることを利用する。\(M = j - i + 1\)として、この時、組\((l, r)\)の選び方は、\(l \lt r\)を満たすものが\({}_M \mathrm{C}_2\)通りあり、項数1の数列も等差数列に含まれることに注意すると\(l = r\)を満たすものが\(M\)通り存在するため、\begin{equation} ( {}_M \mathrm{C}_2 + M ) \text{    通り}  \tag{7} \end{equation}であると分かる。この構造を見抜くことができれば、尺取り法を利用した方針が有効であるという発想に至る(いつもは区間\([l, r)\)を対象とした尺取り法を利用しているが、今回は区間\([l, r]\)が対象となり、個人的にはこの形式にあまり慣れておらず割と長めの時間を食ってしまったのが悔しい)。出力すべき答えを格納する変数\(ans\)を\(0\)、数列\(A\)の添字\(l, r\)の2つを\(0\)で初期化し、公差を記憶する変数\(d\)を用意し、以下のように\(l, r\)を動かして答えを求めよう。

1)\(r = N - 1\)が成り立っているのならば、式(7)で求められる値を\(ans\)に加算して(※)繰り返しを抜け出る。成り立っていなければ2)へ進む。

2)\(l = r\)が成り立っているのならば、\(r\)に\(1\)を加算し、\(d\)の値を\(A_r - A_l\)で更新する。成り立っていなければ3)へ進む。

3)\(A_{r + 1} - A_r = d\)が成り立っているのならば\(r\)に\(1\)を加算する。成り立っていなければ4)へ進む。

4)式(7)で求められる値を\(ans\)に加算し(※)、\(l\)の値を\(r\)で更新する。その後、また1)からの判定を順番に行う。

(※)について、\(ans\)に加算する処理を行う時点で\(l \ne 0\)である場合には、\(ans\)に対して加算を行った後に\(1\)を減算しなければならないことに注意。例えば数列\(A\)の中身が\begin{equation} 1, 6, 11, 9, 7, 5 \end{equation}という6項からなるものであるとすると、\(A_0\)から\(A_2\)までが公差\(5\)の等差数列で、\(A_2\)から\(A_5\)までが公差\(-2\)の等差数列である。この時に上記1)から4)の流れを進めていくと、まず\((l, r) = (0, 2)\)に達すると4)が実行され、\(0 \le l \le r \le 2\)を満たす\((l, r)\)についての組の数を数え上げることになる。その後は\((l, r) = (2, 5)\)に達すると1)が実行され、\(2 \le l \le r \le 5\)を満たす\((l, r)\)についての組の数を数え上げることになる。これら2回において、\((l, r) = (2, 2)\)という組がどちらの場合でも数え上げられてしまっているので、この影響を解消すべく、後者の場合には\(1\)を引く必要がある。

以上の処理を終えた後の\(ans\)を出力してAC獲得。計算量を雑に見積もると、2つの添字\(l, r\)を先頭から末尾へ動かすだけなので\(\mathcal{O}(N)\)の処理時間となる。

 

<D問題>

↓問題のページ↓

D - Bonus EXP

 

(個人的には)比較的慣れ始めてきた動的計画法を利用する問題。この問題に関しては evima氏の動画 が非常に簡便であるためなるべくそちらを参考に実装するのが望ましい。

自分は各状態を「先頭の\(i\)匹目までを倒すか否かを決めており、\(i\)匹目を倒すか否かの選択が\(j\)であり(\(j\)が\(0\)ならば倒さず、\(1\)ならば倒す)、\(i\)匹目までで倒してきた敵の数を2で割った余りが\(k\)である」と定義した(以下、この状態を\(S(i, j, k)\)と記載することにする)ため、\(j\)の部分がまるごと無駄になっている。一応この後の詳細を書いておく。

1)\((i + 1)\)匹目を倒さない場合

\(j, k\)の値によらず、\(S(i, j, k)\)から\(S(i + 1, 0, k)\)という状態へと遷移する。その際、経験値を獲得することはない。この時、仮に\(S(i, j, k)\)の時点で最大の経験値を得られていないのならば、遷移先である2つの状態\(S(i + 1, 0, 0), S(i + 1, 0, 1)\)に到達した時点における経験値の合計が最大になることはない。

2)\((i + 1)\)匹目を倒す場合

\(k = 0\)ならば、\(S(i, j, k)\)から\(S(i + 1, 1, 1)\)という状態へと遷移する。その際、(\(i\)匹目までを倒すか否かの選択が如何様であるかには一切関係なく)経験値\(A_i\)を獲得する。\(k = 1\)ならば、\(S(i, j, k)\)から\(S(i + 1, 1, 0)\)という状態へと遷移する。その際、(\(i\)匹目までを倒すか否かの選択が如何様であるかには一切関係なく)経験値\(2A_i\)を獲得する。以上のことから、1)と同様に、仮に\(S(i, j, k)\)の時点で最大の経験値を得られていないのならば、遷移先である2つの状態\(S(i + 1, 1, 0), S(i + 1, 1, 1)\)に到達した時点における経験値の合計が最大になることはない。

1)2)の考察より、動的計画法による解法が有効という結論に至る。まずは以下のように\(dp(i, j, k)\)を定義する。

\(dp(i, j, k) := \) 状態\(S(i, j, k)\)における最大の獲得経験値

ただし\(0 \le i \le N \land j \in \{ 0, 1 \} \land k \in \{ 0, 1 \}\)である。まず、\(dp(i, j, k)\)の初期値を考えると、初期状態では敵を1匹も倒しておらず、他の状態には到達していないので以下のようになる。\begin{equation}
  dp(i, j, k)=
  \begin{cases}
    0 & \text{if } i = 0 \land j = 0 \land k = 0 \\
    -\infty & \text{otherwise} \\
  \end{cases}
\end{equation}である。次に遷移を考える。上記1)2)の考察に従うと、\(i\)を\(0\)から\(N - 1\)まで、\(j\)を\(0\)から\(1\)まで、\(k\)を\(0\)から\(1\)まで動かしていき、\(dp(i, j, k) \ne -\infty \)の場合のみ、以下のように遷移させると良い。\begin{equation}
    \left\{
    \begin{aligned}
         dp(i+1, 0, k) & = \text{max}(dp(i+1, 0, k), dp(i, j, k) ) \\
         dp(i+1, 1, 1) & = \text{max}(dp(i+1, 1, 1), dp(i, j, k) + A_i ) \text{   if } k = 0 \\
         dp(i+1, 1, 0) & = \text{max}(dp(i+1, 1, 1), dp(i, j, k) + 2 A_i ) \text{   if } k = 1 \\
    \end{aligned}
    \right.
\end{equation}このようにして求められた\(dp(N, j, k)\)のうちの最大値を出力してAC獲得。計算量を雑に見積もると、基本的に添字\(i\)を先頭から末尾へ動かすだけで、それに\((j, k)\)の組み合わせが4通り生えてくるだけなので\(\mathcal{O}(N)\)の処理時間となる。


Viewing all articles
Browse latest Browse all 8866

Latest Images

Trending Articles