105633K - Scheduling Two Meetings

  • 给定 N×MN \times M 的 01 矩阵 AA
  • 选取两行 i,ji, j,满足对于所有列 mm,有 Ai[m]=1A_{i}[m] = 1Aj[m]=1A_{j}[m] = 1 至少一者成立。
  • 最大化满足 Ai[m]=1A_{i}[m] = 1Aj[m]=1A_{j}[m] = 1 的列数。
  • 输出所选的 iijj。若有多种选择,则选择 ii 最小的对;若 ii 相同,则选择 jj 最小的对。
  • 2N2×1052 \le N \le 2 \times 10^52M202 \le M \le 20
  • 给定长度为 NN 的非负整数数组 AA,其中每个元素 0Ai<2M0 \le A_{i} < 2^M
  • 选取两个下标 i,ji, j,满足 AiAj=2M1A_{i} \mid A_{j} = 2^M - 1,并最大化 popcount(Ai & Aj)\operatorname{popcount}(A_{i} \ \& \ A_{j})
  • 若有多种选择,则选择 ii 最小的对;若 ii 相同,则选择 jj 最小的对。
  • 2N2×1052 \le N \le 2 \times 10^52M202 \le M \le 20

特判 Ai=Aj=2M1A_{i}=A_{j}=2^M - 1,否则一定有 AiAjA_{i} \neq A_{j}

为了让 AiAj=2M1A_{i} \mid A_{j} = 2^M - 1AjA_{j} 必须在 AiA_{i} 为 0 的位上全为 1。换句话说,AjA_{j} 必须是 AiA_{i} 按位取反的超集。维护每个 ss 的第一次出现下标,做超集和,然后拼接即可。

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
std::vector<std::pair<int, int>> f(1 << M, { inf, inf });
std::vector<int> nb;
for (int i = 0; i < N; i++) {
unsigned mask = A[i];
if (mask == ((1 << M) - 1)) {
nb.push_back(i);
}
chmin(f[mask], { -std::popcount(mask), i });
}

if (nb.size() > 1) {
std::cout << nb[0] + 1 << " " << nb[1] + 1 << std::endl;
return;
}

auto g = f;
for (int bit = 0; bit < M; bit++) {
for (unsigned mask = 0; mask < 1 << M; mask++) {
if (mask >> bit & 1) {
chmin(g[mask ^ (1 << bit)], g[mask]);
}
}
}

std::array<int, 3> res { inf, inf, inf };
for (unsigned mask = 0; mask < 1 << M; mask++) {
auto [val1, id1] = f[mask];
auto [val2, id2] = g[((1 << M) - 1) ^ mask];
if (id1 != inf && id2 != inf && id1 != id2) {
chmin(res, { val1 + val2, id1, id2 });
}
}

if (res[0] == inf) {
std::cout << "No" << std::endl;
} else {
auto [val, id1, id2] = res;
if (id1 > id2) {
std::swap(id1, id2);
}
std::cout << id1 + 1 << " " << id2 + 1 << std::endl;
}