CF2042C 题解
被硬控 1 h。
令 \(a_i\) 表示第 \(i\) 个元素。
首先做个转化:\(1 \to +1, 0 \to -1\)。考虑把每个元素各分成一组,此时每个元素的权值分别为 \(0, 1, 2, \cdots, n - 1\)。
以 \(n = 6\) 举例。如果我们把位置 \(3, 4\) 合并成一组,那么权值会变成 \(0, 1, 2, 2, 3, 4\),相当于在位置 \(4\) 后缀减 \(1\),此时答案减少 \(a_4 + a_5 + a_6\)。
从特殊到一般,我们可以发现,如果把位置 \(i, i + 1\) 合并成一组,那么答案减少 \(\sum \limits_{j = i + 1}^n a_i\)。
设后缀和 \(S_i = \sum \limits_{j = i}^n a_i\),则我们按 \(S_i\) 从小到大排序,依次把答案减 \(S_i\),能减几次就减几次。
注意 \(S_1\) 减不了,要跳过。
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3f;
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
int t;
cin >> t;
while (t-- > 0) {
int n, k;
string s;
cin >> n >> k >> s;
vector<int> suf_sum(n);
suf_sum[n - 1] = (s[n - 1] == '1' ? 1 : -1);
for (int i = n - 2; i >= 0; --i)
suf_sum[i] = suf_sum[i + 1] + (s[i] == '1' ? 1 : -1);
i64 cur = 0;
for (int i = 0; i < n; ++i)
cur += i * i64(s[i] == '1' ? 1 : -1);
int i, ans = n;
suf_sum.erase(suf_sum.begin());
--n;
sort(suf_sum.begin(), suf_sum.end());
for (i = 0; i < n && suf_sum[i] <= 0; ++i) {
--ans;
cur -= suf_sum[i];
}
if (cur < k) {
cout << "-1\n";
continue;
}
for (; i < n; ++i) {
if (cur - suf_sum[i] >= k) {
cur -= suf_sum[i];
--ans;
} else
break;
}
cout << ans << '\n';
}
return 0;
}

浙公网安备 33010602011771号