思路
考虑贪心,经过手玩样例发现,在 \(1\) 不是连续的情况下,\(1\) 的个数是奇数时,每个 \(1\) 都向中间的 \(1\) 的位置交换时最优。\(1\) 的个数是偶数时,每个 \(1\) 都向 \(1\) 的个数除 \(2\) 的那个 \(1\) 的所在位置交换更优。
那么新的问题就来了,设目标位置为 \(k\) ,那么 \(i\) 这个位置的 \(1\) 要换到那个位置呢?答案是:abs(v[i] - (v[k] - (k - i)));
(\(v_k\) \(v_i\) 表示 \(k\) 和 \(i\) 的位置)为什么呢?因为这个 \(i\) 前面换了 \(k - i\) 个 \(1\),所以这次要换到 \(v_k\) 前第 \(k - i\) 个位置。然后这题就做完了,记得要特判 \(1\) 最开始是不是连续的。
代码
#include <bits/stdc++.h>
#define ll long long
#define N 500001
#define mod 998244353
#define all(a) a.begin(),a.end()
#define uniqueu(a) a.erase(unique(all(a)), a.end())
using namespace std;
mt19937_64 mrand(random_device{}());int n;
string s;
int v[N], l;int main() {ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);cin >> n >> s;bool ok = true;for (int i = 0; i < n; i++) {if (s[i] == '1' && (i == 0 || s[i - 1] == '0') && ok)ok = false;if (s[i] == '1' && s[i - 1] == '0' && !ok)ok = true;}if (!ok) {cout << "0\n";return 0;}for (int i = 0; i < n; i++)if (s[i] == '1')v[++l] = i + 1;int k = l / 2;if (l % 2)k++;ll ans = 0;for (int i = 1; i <= l; i++)ans += abs(v[i] - (v[k] - (k - i)));cout << ans << "\n";
}