人間だけど競プロやる

解けなかった問題を理解できたら記事を投稿します。日本語の解説が見つからなかったもの中心。

Codeforces Round #666 (Div. 2) C. Multiples of Length

Codeforces Round #666 (Div. 2) C. Multiples of Length

長さN1\leq10^5)の配列a_n-10^9\leq a_i \leq 10^9)が与えられる。
操作を3回行って、全ての要素を0にせよ。


気づき

  1. 任意の長さの配列を3回の操作ですべて0にできることが証明できると書いてあるので、選択肢は多くない。
  2. 選択した範囲の長さをLとするとき、a_iをゼロにできるというのは、a_iLの倍数であること。
  3. 全ての要素をNの倍数にできれば良さそう


2.については自明とする


1.について
まず、すべての要素について少なくとも2回は操作しないといけない。(\because 一回の操作で0になるのは、a_iが運良くLの倍数のときだけ)
よって考えられる範囲の決め方として、

  • 任意の位置xで区切って、「左、右、全体」
  • 「全体、全体、全体」

しか考えられない(いまは順番のことは考えていない)
しかし、同じ範囲を連続で2回えらぶのは明らかに損なので、前者しか候補にならない。
\because 全体を選ぶということはa_iNの倍数を足すことなので、連続で選ぶなら、一回目で2 \times Nの倍数を足せば同じ結果になる)


3.について
任意の位置xで区切ったとき、左の範囲の長さをL、右の範囲の長さをL2とする。

  • a_iに全体の長さNの倍数を足して、左側をLの倍数に、右側をL2の倍数にする。
  • 左側の範囲にLの倍数を足して、右側の範囲にL2の範囲をたして、全体をNの倍数にする

のうち、どちらが実現できそうかを考える。
直感的に、一つの操作で2つの状態(Lの倍数、L2の倍数)へ遷移するより、1つの状態(Nの倍数)へ遷移したほうが素直な操作だと考える(微粒子レベルのエスパー)
よって、「左、右、全体」の順番で操作して、全体を0にすることを考える。
つまり、左側にLの倍数を足して、右側にL2の倍数をたして、全体をNの倍数にすることを考える。


以上より、全体をNの倍数にすることを考える
単純にNの倍数にするなら全てのa_ia_i \times Nに変換できれば良い。(この問題のエスパー部分)
ひとまず、KL2の倍数として立式してみると、

\displaystyle{K+a_i=N \times a_i}
\displaystyle{K=a_i(N-1)}
となり、KL2の倍数なので、Aを任意の整数として、
\displaystyle{L2 \times A = a_i(N-1)}
\displaystyle{L2=\frac{N-1}{A}}

L2自然数かつN-1は任意の自然数なので、(N-1素数かもしれない)
A=N-1,\ 1
よって、L2=N-1のときL=1となり、L=1のときa_iは必ず0にすることができる(\because 任意のa_i1の倍数)ので、L=1L2=N-1で全てのa_nについて0にできることがわかる。
L2=N-1のときL=1L2=1のときL=N-1となり片方を考えれば良い)


したがって、

  1. [1,1] を選び、a_1 \times -1を足す(a_1を0にする)。
  2. [2,N] を選び、a_i \times (N-1)を足す(a_iNの倍数にする)。
  3. [1,N] を選び、N \times a_i \times  -1を足す(a_i0にする)。


この順の操作で、任意のa_nについて、すべての要素を0にできる。
N-1の倍数として0を使うことができることに留意)
ただし、N=1(与えられる配列の長さが1)の場合の実装に注意が必要!