2020年9月14日月曜日

CodeChef September Challenge 2020 - Chefina and Swap

0-basedで考える。列(Si)(S_i)[0,m),[m,N)[0, m), [m, N)に分けた時に、左右の和を等しくするようなスワップが何個あるか数える。まず、右の和のほうが大きいことが有効なスワップが存在する必要条件である。右の和が左の和よりD(m)D(m)だけ大きいとする。このとき、D(m)D(m)が偶数なら左の区間のSiS_iと右の区間のSi+D(m)/2S_{i+D(m)/2}を交換すると和が等しくなる。添え字iiが有効である条件は0i<m,mi+D(m)/2<N0\le i < m, m \le i+ D(m)/2 < Nで、これはmax(0,mD(m)/2)i<min(m,ND(m)/2)\max(0, m-D(m)/2) \le i < \min(m, N-D(m)/2)とまとまる。この区間の長さが有効なスワップの数に等しいので、すべてのmmについて足せばよい。ただしD(m)=0D(m)=0の場合は区間をまたいで数を移動する必要がないので特別扱いして、左の区間内と右の区間内のスワップの総数を数える。

さて、0D(m)<2N0\le D(m) < 2Nが必要なことを考えると、有効なmmは多くないはずだ。mmが増加するとき、D(m)D(m)が正から負に変わる地点を考えると、この地点は全体の半分よりは右にあるはずだから、その付近ではmm11動くごとにおおむね2N/2=N2 \cdot N/2 = N程度はD(m)D(m)が変化することになる。したがって、高々3つ程度のmmについて数えれば十分という見積もりができる。実装の際はD(m)0D(m) \ge 0であるような最大のmmを二分探索などで求めておいて、そこから下っていけばよい。