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;
}
posted @ 2025-08-27 22:57  David9006  阅读(15)  评论(0)    收藏  举报