专栏文章

题解:P12676 相等排列

P12676题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mip4vd0u
此快照首次捕获于
2025/12/03 06:12
3 个月前
此快照最后确认于
2025/12/03 06:12
3 个月前
查看原文

思路

题目的目标是将分散的 1 尽可能合并成连续块,最小化最终块数。令 StS_t 表示位置 ttt+1t+1 两个 1 之间的连续 0 数量。当 k>SA>SBk > S_A > S_B 时,优先填补 [B,B+1][B,B+1][A,A+1][A,A+1] 更优(同样操作次数能合并更多块)
提取所有 1 的位置索引,统计相邻 1 间的 0 数量 然后按间隙大小升序排序,接着用操作数 kk 优先填补小间隙

代码实现

CPP
#include <bits/stdc++.h>
using namespace std;

int main() {
    int n, k;
    scanf("%d%d", &n, &k);
    vector<int> ones;  // 存储所有 '1' 的位置索引

    // 读取序列并记录 '1' 的位置
    for (int i = 0; i < n; ++i) {
        char c;
        scanf(" %c", &c);
        if (c == '1') ones.push_back(i);
    }

    // 特判:无 '1' 直接结束
    if (ones.empty()) {
        printf("0\n");
        return 0;
    }

    // 计算初始块数(连续 '1' 视为单块)
    int blocks = 1;
    for (int i = 1; i < ones.size(); ++i) {
        if (ones[i] != ones[i-1] + 1) blocks++;
    }

    // 提取块间间隙(忽略块内间隙)
    vector<int> gaps;
    int prev_end = ones[0];  // 当前块末尾位置
    for (int i = 1; i < ones.size(); ++i) {
        if (ones[i] != ones[i-1] + 1) {  // 发现新块
            int gap = ones[i] - prev_end - 1;  // 计算间隙
            if (gap > 0) gaps.push_back(gap);
            prev_end = ones[i];  // 更新块尾
        } else {
            prev_end = ones[i];  // 同一块内移动
        }
    }

    sort(gaps.begin(), gaps.end());  // 按间隙升序排序

    // 贪心填补:优先消耗小间隙
    int merged_blocks = 0;
    for (int g : gaps) {
        if (k >= g) {
            k -= g;
            merged_blocks++;  // 每填一隙减少一个块
        } else break;
    }

    // 输出:初始块数 - 成功合并数
    printf("%d\n", blocks - merged_blocks);
    return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...