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;
}