Loading

AtCoder Beginner Contest 393-D Swap to Gather题解

思路

考虑贪心,经过手玩样例发现,在 \(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";
}
posted @ 2025-02-16 13:39  笙竺  阅读(31)  评论(0)    收藏  举报