D - Swap to Gather Editorial by en_translator
Among several possible solutions, here we will introduce the one that is (presumably) easiest to implement. Before going into long mathematical explanation, here is an intuitive understanding:
Intuitive explanation
For each0
in $S$, consider the number of 1
to its left (let it be $l$) and the number of 1
to its right (let it be $r$). If $l< r$, it's better to bring 0
to the left of the 1
chunk. If $l< r$, it's better to bring 0
to the left of the 1
chunk. Thus, the answer is the sum of $\min\{l,r\}$ for all 0
.
Let \(C_0\) be the number of 0
in \(S\), and \(C_1\) be the number of 1
\((=N-C_0)\).
For each \(i\ (1\leq i\leq C_0)\), let \(d_i\) be the number of 1
s to the right of the \(i\)-th 0
from the left. For convenience, define \(d_0=0\) and \(d_{C_0+1}=C_1\). Then \(d_0 \leq d_1\leq d_2\leq \dots \leq d_{C_0}\leq d_{C_0+1}\).
Let us reinterpret the problem according to the value \(d_i\). First, swapping the same character is meaningless, so the operation in the original problem statement is equivalent to performing one of the following operations against \(d_i\):
- Choose one \(i\ (1\leq i\leq C_0)\) with \(d_{i-1}<d_i\), and decrease \(d_i\) by \(1\).
- Choose one \(i\ (1\leq i\leq C_0)\) with \(d_i<d_{i+1}\), and increase \(d_i\) by \(1\).
The termination condition is as follows:
- There exists \(p\ (0\leq p\leq C_0)\) such that \(0=d_1=\dots=d_p\) and \(d_{p+1}=\dots=d_{C_0}=C_1\).
One operation changes \(d_i\) by one, so clearly at least \(K\) operations is required, where
\[K=\displaystyle\sum_{i=1}^{C_0} \min\{d_i, C_1-d_i\}.\]
On the other hand, since \(d_i\) is monotonically increasing, it is always possible to satisfy the termination condition with \(K\) operations, so the answer is \(K\). (One can let \(p\) be the largest \(i\) with \(d_i < C_1-d_i\), or \(0\) if it does not exist.)
Sample code (C++):
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
string s;
cin >> n >> s;
int c1 = 0;
for (char c: s) {
if (c == '1') ++c1;
}
int now = 0;
long long ans = 0;
for (char c: s) {
if (c == '0') {
ans += min(now, c1 - now);
} else {
++now;
}
}
cout << ans << endl;
}
posted:
last update: