CF1408H Rainbow Triples 题解

Description

给定长度为 nn 的序列 pp

找出尽可能多的三元组 (ai,bi,ci)(a_i,b_i,c_i) 满足:

  • 1ai<bi<cin1\le a_i<b_i<c_i\le n
  • pai=pci=0p_{a_i}=p_{c_i}=0pbi0p_{b_i}\ne 0
  • pbip_{b_i} 互不相同。
  • 所有的 ai,bi,cia_i,b_i,c_i 互不相同。

输出最多可以选出多少个三元组,多组数据。

n5105\sum n\le 5\cdot 10^5

Solution

设总共有 cc00,容易发现答案的上界是 c2\left\lfloor\frac{c}{2}\right\rfloor,并且对于每个三元组,aia_i 一定在前 c2\left\lfloor\frac{c}{2}\right\rfloor 个,cic_i 一定在最后 c2\left\lfloor\frac{c}{2}\right\rfloor 个。

因为如果不满足那么调整成这个情况一定更优。

然后考虑一个 bib_i,如果在前 c2\left\lfloor\frac{c}{2}\right\rfloor00 的区间里,那么如果它能够与 c2\left\lfloor\frac{c}{2}\right\rfloor 匹配那么一定能和右边的 00 匹配,如果在右边则一定能与左边的 00 匹配。

所以只要把 midmid 左边和右边的分开考虑然后把答案相加与 c2\left\lfloor\frac{c}{2}\right\rfloor 取 min。

容易发现对于一个颜色,只有 <mid<mid 的最大位置和 >mid>mid 的最小位置有意义,所以把这个颜色与 <mid<mid 的位置之前的 00>mid>mid 的位置之后的 00 连边跑网络流即可,显然过不了。

注意到一个颜色匹配的一定是一个前缀+一个后缀,所以把 midmid 之前的 00 移到最后面,那么每个颜色匹配的就是一个区间 [l,r][l,r],于是只要先按 rr 排序然后贪心即可。

时间复杂度:O(nlogn)O(n\log n)

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <bits/stdc++.h>

// #define int int64_t

const int kMaxN = 5e5 + 5;

int n;
int a[kMaxN];
std::vector<int> vec[kMaxN];

void dickdreamer() {
std::cin >> n;
for (int i = 0; i <= n; ++i) vec[i].clear();
for (int i = 1; i <= n; ++i) {
std::cin >> a[i];
vec[a[i]].emplace_back(i);
}
// if (vec[0].size() & 1) vec[0].erase(vec[0].begin() + vec[0].size() / 2);
if (!vec[0].size()) return void(std::cout << "0\n");
int cnt = vec[0].size(), L, R;
if (vec[0].size() & 1) L = R = vec[0][(vec[0].size() - 1) / 2];
else L = vec[0][vec[0].size() / 2 - 1], R = vec[0][vec[0].size() / 2];
std::vector<std::pair<int, int>> rg;
for (int i = 1; i <= n; ++i) {
if (!vec[i].size()) continue;
int id1 = -1, id2 = n + 1;
for (auto x : vec[i]) {
if (x < R) id1 = x;
if (x > L && id2 == n + 1) id2 = x;
}
id1 = std::lower_bound(vec[0].begin(), vec[0].end(), id1) - vec[0].begin() - 1;
id2 = std::lower_bound(vec[0].begin(), vec[0].end(), id2) - vec[0].begin();
rg.emplace_back(id2, cnt + id1);
}
auto cmp = [](const std::pair<int, int> &p1, const std::pair<int, int> &p2) {
return std::make_pair(p1.second, p1.first) < std::make_pair(p2.second, p2.first);
};
std::sort(rg.begin(), rg.end(), cmp);
std::set<int> st;
for (int i = 0; i < 2 * cnt; ++i) st.emplace(i);
int ans = 0;
for (auto p : rg) {
auto it = st.lower_bound(p.first);
if (it != st.end() && *it <= p.second) ++ans, st.erase(it);
}
std::cout << std::min(ans, cnt / 2) << '\n';
}

int32_t main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
int T = 1;
std::cin >> T;
while (T--) dickdreamer();
// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}

CF1408H Rainbow Triples 题解
https://sobaliuziao.github.io/2024/02/28/post/b266b960.html
作者
Egg_laying_master
发布于
2024年2月28日
许可协议