Processing math: 100%

AtCoder Beginner Contest 240 F,G問題メモ

AtCoder Beginner Contest 240

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

F - Sum Sum Max

問題

  • 整数列 C は、x1xN,y1yN を使って以下のように表される
    • x1y1 個、x2y2 個、…… xNyN 個、この順に繋げた数列
  • 整数列 B は、C の先頭からの累積和である
  • 整数列 A は、B の先頭からの累積和である
  • A の最大値を求めよ
  • T 個のテストケースが与えられるので、それぞれについて求めよ
  • 1つのテストケースにおける整数列の長さ 109
  • 1つの入力に含まれる全テストケースの N の総和 2×105

解法

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 の最大値を求める上では、Bi と比べて Bi+1 が正なら次も足した方がいいし、負ならそこでひとまず止めた方がいい。

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

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

       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

切り替わり点の ij1,j2,... と表す。
Bjk は、単に xk×yk を累積的に足していけば求められる。
BjkBjk+1 を比べると、その中に A の最大値があり得るかどうかわかる。

  • 正→正: 末尾が最大
  • 負→正: 末尾か先頭が最大
  • 負→負: 先頭が最大
  • 正→負: 「途中に、正から負に切り替わる=最大値を取りうる箇所が存在する」

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

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

切り替わり点から i が1つ進む毎に xk だけ減っていくので、Bjk1xk(切り捨て)だけ進んだ箇所が正、その次が負となる。

       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 進んだ箇所が最大値をとるとわかったので、A6 を求める。

先頭から累積的に計算することで、Aj1,Aj2,... は計算できる。

       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つ前の区間の終わりが Ar で、その次に C において n 個の xi が並んでいると、

  • Ar+n=Ar+Br×n+n(n+1)2×xi

と表現できる。

これを使うと、A6=A4+B4×d+d(d+1)2×x3=13 となり、正しく求められている。

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

Python3

G - Teleporting Takahashi

問題

  • 3次元グリッド上で、隣接する6つの立方体のいずれかに移動することを繰り返す
  • 原点 (0,0,0) からちょうど N 回の移動後に (X,Y,Z) に存在する移動方法の個数を mod998244353 で求めよ
  • 1N107

解法

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

2次元の場合

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

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

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

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

  • x 軸方向に m 回の無駄を挟むなら、計 X+2m 回の移動の中で目標と反対に移動する m 回の位置を決めればよい
    • X+2mCm

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

3次元の場合

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

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

Python3

programming_algorithm/contest_history/atcoder/2022/0220_abc240.txt · 最終更新: 2022/02/23 by ikatakos
CC Attribution 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0