CF1779D Boris and His Amazing Haircut
题目
分析
应该让每一个 \(x\) 覆盖尽量大的区间。
分析题目,可以知道对于每一个位置 \(i\),有多少 \(x > b[i]\) 覆盖了 \(i\) 是不关键的,关键是是否有一个 \(x \leq b[i]\) 是否覆盖了它。
当位置 \(i\) 被 \(x < b[i]\) 覆盖,那这个位置会变成 \(x\) 而不是 \(b[i]\),就变不回来了,这是我们所不希望看到的。所以我们必须让 \(x \ge b[i]\) 覆盖 \(i\)。这样,就得出 \(x\) 不能覆盖 \(i\) 的条件:\(x < b[i]\)。
有了上面的几个条件,我们就可以非常轻松的想出这题的解法:循环遍历每一个 \(i\),同时整一个 set 用来存目前的所有正在用的操作 \(x\)。循环过程中,有以下两种情况:
- 当前的 \(b[i]\) 包含在 set 中,那就什么也不干,继续往下走;
- 不包含,那就在所有还没用过的 \(x\) 中找一个与 \(b[i]\) 相等的 \(x\),并将这个 \(x\) 扔到 set 里,表示这个 \(x\) 正在被用,同时将其从还没用过的 \(x\) 中删掉。如果发现没有与 \(b[i]\) 相等的 \(x\) 没被用过,那就终止循环,答案为 NO。
在循环到某些位置 \(i\) 时,由于 set 中有些 \(x\) 会小于 \(b[i]\),所以需要实时地把这些 \(x\) 扔出去。因为一个操作的作用区间一定是连续的,所以如果这个 \(x\) 在 \(b[i]\) 这个地方不能用了,那这后面一定都不能用这一个 \(x\)。
附代码:
#include <iostream> // 懒得用 bits 的屑博主
#include <set>
using namespace std;
int a[200005], b[200005]; // 如题目,顾名思义
multiset<int> st, oks; // st 用来存还没有没用过的 x,oks 用来存正在被用的 x
int main() {
set<int>::iterator it; // set 的迭代器,用来遍历 set / multiset,应该是一种指针
int tc, n, m; // n, m 如题意
scanf("%d", &tc);
while (tc--) {
oks.clear(); // 初始化
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", a + i);
}
for (int i = 0; i < n; i++) {
scanf("%d", b + i);
}
scanf("%d", &m);
st.clear(); // 初始化
int tmp;
for (int i = 0; i < m; i++) {
scanf("%d", &tmp);
st.insert(tmp); // 这个 x 还没有被用过
}
bool flag = true; // 答案
for (int i = 0; i < n; i++) {
if (b[i] > a[i]) {
flag = false; // 由于操作不能把一个数变大,所以就有了这句话
break; // 直接退循环
} else if (b[i] == a[i]) {
while (!oks.empty() && *oks.begin() < b[i]) { // 因为 set 默认从小到大排序,所以如果有一个 x 不合要求,
oks.erase(oks.begin()); // 那这个 x 一定排在前面(x 的不合规性满足单调性)
}
} else {
while (!oks.empty() && *oks.begin() < b[i]) oks.erase(oks.begin()); // 同上
if (oks.count(b[i]) == 0 && st.count(b[i]) >= 1) { // 没有与 b[i] 相同的 x 正在被用且还有与 b[i] 相同的 x 可以用
st.erase(st.find(b[i])); // 注意!这里的 st 是可重集,直接用 st.erase(b[i]) 会把所有 b[i] 全删了,导致错误
oks.insert(b[i]); // x 正在被用
} else if (oks.count(b[i]) == 0 && st.count(b[i]) == 0) { //没有与 b[i] 相同的 x 可用了,答案为 NO
flag = false;
break;
} //此处省略了刚才讨论的第一种情况
}
}
cout << (flag ? "YES\n" : "NO\n"); // yee~~~
}
return 0;
}

浙公网安备 33010602011771号