Problem - I - Codeforces
看到最小值最大值,二分答案。
思路:每次二分时开两个集合,分别表示 0 0 0颜色和 1 1 1颜色。如果是 c c c颜色,先将值存入 c c c颜色,之后在 ! c !c !c颜色中找大于等于 m i d − a mid - a mid−a的值。
- 如果找到:删除 c c c颜色中一个值为 a a a的元素和 ! c !c !c颜色中一个值为大于等于 m i d − a mid - a mid−a的元素。
- 没有找到:找不大于 m i d − a mid - a mid−a中最大的值,判断该值是否存在,如果存在则返回 f a l s e false false;否则继续处理。
对于C++的集合erase
函数来说:
set
:set
中的元素是不同的,非多重集。multiset
:虽然元素可以是多个,但是按key
删除是将集合中key
相等的都删除。可以按迭代器删除。
这里提供另一种:将set
中的key
用元组表示,second
用下标表示。这样即使first
值相同,但是second
值不同,实现了每次只删除一个元素。
代码如下:
#include "bits/stdc++.h"
using namespace std;
using LL = long long;
int main()
{
int n; cin>>n;
vector<int> a(n), c(n);
for(auto &t: a) cin>>t;
for(auto &t: c) cin>>t;
LL l = 0, r = 1e9;
auto check = [&](LL mid) -> bool {
set<pair<LL,LL>> s[2];
for(int i = 0; i < n; ++i) {
s[c[i]].insert({a[i], i});
if(s[!c[i]].size()) {
auto pos = s[!c[i]].lower_bound({mid - a[i], -1});
if(pos == s[!c[i]].end()) {
auto it = pos--;
if(it != s[!c[i]].begin()) {
return false;
}
} else {
s[!c[i]].erase(pos);
s[c[i]].erase({a[i], i});
}
}
}
return true;
};
while(l < r) {
LL mid = l + r + 1 >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
cout<<l<<endl;
}