题解:P12505 「ROI 2025 Day2」充实的假期
Hello_Coding · · 题解
Solution
先说明一下,有同学可能会对题意有一些误解。经过模拟样例我们可以发现,“最多能获得的充实休假日数量”指的是充实休假日的天数,也就是说,形如 11011011 的安排应该是算
整体思路:贪心。
考虑将某个
- 当
s_i 为形如01010中间的那个0时,将其从0 变为1 将增加3 个“充实休假日”; - 当
s_i 为形如010左侧或右侧(仅能一侧)的那个0时,将其从0 变为1 将增加2 个“充实休假日”; - 当
s_i 为形如011左侧或110右侧的那个0时,将其从0 变为1 将增加1 个“充实休假日”。
观察数据范围,询问次数
贪心策略告诉我们,我们应优先考虑贡献值最高的 a 情况,其次 b,最后 c。值得注意的是,c 情况会在 a 与 b 之后考虑,因此做完 a、b 情况后剩余的 0 一定满足 c 情况的 011 或 110。
对于每一个
对于这种分类讨论题,基本都有特判的坑。此题若字符串 0,不在讨论范围内,需要特判:如果
具体详见代码,如下。
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 1e5 + 5;
int n, q, k, cnt = 0, ans = 0, chg[N];
string s;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cin >> n >> q >> s;
s = '0' + s + '0';
// spj
bool all_zero = *max_element(s.begin(), s.end()) == '0';
// init
int t = 0;
for (int i = 1; i <= n + 1; i++) {
if (s[i] == '1') t++;
else {
if (t > 1) chg[0] += t;
t = 0;
}
}
// +3
for (int i = 0; i <= n - 3; i++) {
if (s.substr(i, 5) == "01010") {
chg[++cnt] = 3;
s[i + 2] = '1';
}
}
// +2
if (s.substr(1, 2) == "10") {
chg[++cnt] = 2;
s[2] = '1';
}
if (s.substr(n - 1, 2) == "01") {
chg[++cnt] = 2;
s[n - 1] = '1';
}
for (int i = 1; i <= n - 2; i++) {
if (s.substr(i, 3) == "010") {
chg[++cnt] = 2;
s[i] = '1';
}
}
// +1
while (cnt < n) chg[++cnt] = 1;
// get sum
for (int i = 1; i <= cnt; i++) chg[i] += chg[i - 1];
// ans
while (q--) {
cin >> k;
if (all_zero && k == 1) cout << 0 << '\n';
else cout << chg[k] << '\n';
}
return 0;
}