sky’s 雑記

主にAndroidとサーバーサイドの技術について記事を書きます

第一回日本最強プログラマー学生選手権-予選- B - Kleene Inversion

atcoder.jp

学生対象だが10歳くらいオーバーしてるおっさんですまん。

初手の方針

今回はスムーズに方針立てられた、 以下2つの転倒数の和の合計を取る。

  1. A中に含まれる転倒数の合計
  2. AkiとAkj,Akj+1...Akの転倒数の合計

入力例3で説明する。

10 998244353
10 9 8 7 5 6 3 4 2 1

1個目のAの集合をA1={10 9 8 7 5 6 3 4 2 1}とすると、 1. A中に含まれる転倒数の合計 これは10->9 8 7 5 6 3 4 2 1, 9-> 8 7 5 6 3 4 2 1, 8-> 7 5 6 3 4 2 1...で合計は43 2. AkiとAkj,Akj+1...Akの転倒数の合計 は1個となりのA2={10 9 8 7 5 6 3 4 2 1}と比較して合計45

1.は集合がK個あれば

S1 = 43K

2.は初項43,公差43,項数K-1の等差数列の和と見なして

S2=k(k-1)/2

となりS=S1+S2が転倒数の合計となる。

Submission #9315505 - Japanese Student Championship 2019 Qualification

本日の気付き

方針を立てるのは比較的簡単だったのだがACを通すのはかなり苦労した。 というのもcppにおけるオーバーフローの挙動をよく理解していなかったからだ。 最終的な合計値を10^ 9+7で割れば良いと思っており(S1+S2)%10^ 9+7していたが、 注意しなければならないのはS1,S2それぞれもオーバーフローする可能性があるということだ。 加減乗についてはオーバーフローの可能性があるものについては%MODする、除については順番に気をつけるといったことが必要そうだ。

qiita.com