ABC288D 別解法メモ

前書き

なるべく愚直な操作でなんとかする解法です。(実質的には同じかもしれませんが、)mod  K での累積和を使っていません。

コンテスト中、解法が思いつかずになんとかして無理やり解く方法を考えたもので、綺麗な解法ではないです。

公式解説を読むほうが勉強になると思います。

問題

atcoder.jp

考え方

  •  l_i=1であれば、左から順に可能な限り0にしていき、0にできない残り K-1個が0になっているかを確かめればよい
  •  l_i \ne 1であるときは、一旦左から順に0にしていったあと、左から 元の数列の値に戻していく ことを考えていく
  • すると、 l_iから K-1個については、0ではない値になる

  • 「左から0にする」操作のあと、「左から元の数列に戻す」ということをすると、0で初期化された長さ r - l + 1の数列に範囲の右から K - 1個の値と左から K-1個の値をそれぞれ足した数列ができる
  • 範囲の長さが 2(K - 1)以上のとき:
    • 範囲左右端の値の間は、 r - l + 1 - 2 (K - 1) = r - l - 2K + 3個の0で埋められることになる
    • ここで、 0, \dots, 0, a (0はK個)は、操作で a, 0, \dots, 0にすることができる*1
    • つまり、 r - l - 2K + 3個の0は、(r - l + 3) \% K個でも同じになるため、最終的にできる数列の長さは  3(K-1)以下にできる
  • あとは、できた数列に対して愚直に操作を実行して、すべて0にできるか確かめればよい
  • 計算量について:
    • 範囲の両端の K-1個の値の事前計算: \mathcal{O}(NK)
    • 愚直に作った数列が0にできるか確かめる計算量:  \mathcal{O}(K^2)
    • よって、全体で  \mathcal{O}(K(N + QK)) で解ける

AC提出

atcoder.jp

なお、

https://

 

ということだそうなので、こちらの考え方を持っておいたほうが活かせる気がしています。

https://twitter.com/chokudai/status/1621872224465727489?s=20&t=rGTI6O6y-GB3eZShdcJysg

*1:本当はもっと強い主張ができる(公式解説参照)。なぜこれがわかったのに、解説のやり方が思いつかなかったのか……