目次

AtCoder Beginner Contest 240 F,G問題メモ

AtCoder Beginner Contest 240

コンテストに参加してたら、数字が綺麗に並ぶ 2022/02/20 22:02:20 をうっかり見逃したので、ABC許さない(とばっちり)

F - Sum Sum Max

F - Sum Sum Max

問題

解法

i   0   1   2   3   4   5   6   7
C  -2  -2   4   4   4  -3  -3  -3
B  -2  -4   0   4   8   5   2  -1
A  -2  -6  -6  -2   6  11  13  12
                          ~~~~   ←最大値

$A$ の最大値を求める上では、$B_i$ と比べて $B_{i+1}$ が正なら次も足した方がいいし、負ならそこでひとまず止めた方がいい。

よって、数列の長さは非常に長くなりうるが、最大値をチェックするのは $B$ が正から負に切り替わるタイミング(と、最初と最後)だけでよい。

それがいつ切り替わるかを直接求めるのは難しいが、$B$ における $N$ 個の $x_i,y_i$ の切り替わり点を追っていけばわかる。

       j1          j2          j3
i   0   1   2   3   4   5   6   7
C  -2  -2   4   4   4  -3  -3  -3
B      -4           8          -1

切り替わり点の $i$ を $j_1,j_2,...$ と表す。
$B_{j_k}$ は、単に $x_k \times y_k$ を累積的に足していけば求められる。
$B_{j_k}$ と $B_{j_{k+1}}$ を比べると、その中に $A$ の最大値があり得るかどうかわかる。

正→負の区間だけチェックすればよいとわかった。

この中で切り替わる具体的な箇所 $i$ を特定し、そこから最大値候補である $A_i$ を求めたい。

切り替わり点から $i$ が1つ進む毎に $x_k$ だけ減っていくので、$\dfrac{B_{j_{k-1}}}{-x_k}$(切り捨て)だけ進んだ箇所が正、その次が負となる。

       j1          j2          j3
i   0   1   2   3   4   5   6   7
C  -2  -2   4   4   4  -3  -3  -3
B      -4           8→ 5→ 2→-1

              B[j2]/-x3 = 8/3 = 2 より、
              i=4 から 2 進んだ i=6 がこの区間の中で最大を取る箇所

前の区間の終わり $i=4$ から $d=2$ 進んだ箇所が最大値をとるとわかったので、$A_6$ を求める。

先頭から累積的に計算することで、$A_{j_1},A_{j_2},...$ は計算できる。

       j1          j2          j3
i   0   1   2   3   4   5   6   7
C  -2  -2   4   4   4  -3  -3  -3
B      -4           8          -1
A      -6           6      []  12

1つ前の区間の終わりが $A_r$ で、その次に $C$ において $n$ 個の $x_i$ が並んでいると、

と表現できる。

これを使うと、$A_6 = A_4 + B_4 \times d + \dfrac{d(d+1)}{2} \times x_3 = 13$ となり、正しく求められている。

正→負となる区間毎に調べていって、$O(N)$ で全て求められる。

Python3

G - Teleporting Takahashi

G - Teleporting Takahashi

問題

解法

2次元なら、過去に類題があった(けどすっかり忘れてた)。

2次元の場合

$N$ 回ちょうどで $(0,0)$ から $(X,Y)$ に移動する。

操作回数が最低限の $|X|+|Y|$ に足りなかったり、偶奇が合わない場合は最初に除く。

最低限から余る移動回数については、 無駄な移動(同じ軸の正方向と負方向の移動のセット)を $k=\dfrac{N-(|X|+|Y|)}{2}$ 回、しなくちゃいけない。

素直に考えると、$x$ 軸方向で何回、$y$ 軸方向で何回行うか決めれば計算できる。 片方の無駄を $0~k$ に固定して場合分けすればよい。 しかし、これだと $O(k)$ かかる。

テクニックとして、45度回転させ、$(+1,+1),(+1,-1),(-1,+1),(-1,-1)$ の4つの移動で $(X+Y,X-Y)$ に到達する、と問題を言い換えると、 2つの軸を独立に考えることができ、2つの二項係数の積で $O(1)$ で計算できてしまう。

3次元の場合

今回の制約では、単純に1次元の無駄回数を $0~k$ で固定して、2次元に帰着させるのを全通り試せばよい。

最初の階乗計算を除けば、全体 $O(N)$ で求められる。

Python3