D - Swap to Gather 解説 by sounansya


\(S\) の中の 1 の個数を \(M\) とします。また、左から \(i\) 番目の 1 の場所を \(A_i\) とします。(この \(i\) は 0-indexed とします)

\(S\) の中の左から \(k\) 文字目から \(k+M-1\) 文字目までに 1 を集めることを考えます。すると、1 同士の相対的な位置関係は変わらないことから、左から \(i\) 番目の 1 は左から \(A_i\) 番目の場所から左から \(k+i\) 番目に移動させれば良いので、全体的な移動回数は \(\displaystyle \sum_{i=0}^{M-1}|A_i-(k+i)|=\sum_{i=0}^{M-1}|k-(A_i-i)|\) となります。

ここで、一般に \(\displaystyle f(x)=\sum_{i=0}^{N-1} |x-X_i|\) の値は \(x\)\(X\) の中央値とすると最小になることが知られています。

\(A\) は狭義単調増加数列であるので、 \(B_i=A_i-i\) は広義単調増加数列となります。よって、 \(B\) の中央値は \(B_{\lfloor M/2\rfloor }\) となるので、 \(k=B_{\lfloor M/2\rfloor }\) とすると操作回数の最小値が得られます。

以上を適切に実装することでこの問題に正答することができます。

実装例(Python3)

n = int(input())
s = input()
a = []
for i in range(n):
    if s[i] == "1":
        a.append(i - len(a))
ki = a[len(a) >> 1]
ans = 0
for i in a:
    ans += abs(i - ki)
print(ans)

投稿日時:
最終更新: