CF1631C And Matching
思路分析
首先我们设 $c(i)$ 为在 $i$ 的二进制表示下,按位取反的结果,
例如:$c(50) = c((110010)_2) = (001101)_2 = 13$,
显然 $c(i) = (n - 1) - i$,
因为 $c(i)$ 是 $i$ 按位取反的结果,所以 $c(i) \& i = 0$
回到原题,我们分 $3$ 种情况:
- $k = 0$,那我们将 $c(i)$ 与 $i$ 进行配对,总和为 $\sum_{i=0}^{n/2-1} c(i) \& i = 0$
- $1 \le k \le n-2$,将 $c(i)$ 与 $i$ 进行配对,考虑把 $0,k,c(k),n-1$ 提取出来,将 $k$ 与 $n - 1$ 配,$k \& (n - 1) = k$,$0$ 与 $c(k)$ 配,$0 \& c(k) =0$,故总和为 $k$,
- $k = n -1$,将 $c(i)$ 与 $i$ 进行配对,考虑把 $0, 1, 2, (n - 3),(n - 2),(n - 1)$ 提取出来,$(n - 1)$ 与 $(n - 2)$ 配对,$(n - 1) \& (n - 2) = (n - 2)$,$1$ 与 $(n - 3)$ 配对,由于 $(n - 3)$ 是奇数,所以 $1 \& (n - 3) = 1$,再将 $0$ 与 $2$ 配对,结果为 $0$,那么总和为 $(n - 2) + 1 + 0+\cdots+0=(n-1)$
注意:在第 $3$ 种情况中,要有至少 $6$ 个数才可以做,所以当 $n=4,k=3$ 时是无解的(样例有)。
这样我们就把题目做完了,复杂度 $O(n)$
代码环节
#include <cstdio>
#include <iostream>
using namespace std;
const int maxn = (1 << 20);
int a[maxn], b[maxn];
int c (int x, int n) {
return (n - 1) - x;
int main() {
int T; scanf ("%d", &T);
while (T --) {
int n, k; scanf ("%d%d", &n, &k);
if (k == 0) {
for (int i = 0; i < n / 2; ++i) {
a[i + 1] = i; b[i + 1] = c(i, n);
}
} else if (k > 0 && k < n - 1) {
a[1] = 0; b[1] = c(k, n);
a[2] = k; b[2] = n - 1;
int cnt = 2;
for (int i = 1; i < n / 2; ++i) {
if (i == c(k, n) || i == k) continue;
a[++cnt] = i; b[cnt] = c(i, n);
}
} else {
if (n == 4) {
printf ("-1\n"); continue;
}
a[1] = 0; b[1] = 2;
a[2] = 1; b[2] = n - 3;
a[3] = n - 2; b[3] = n - 1;
for (int i = 3; i < n / 2; ++i) {
a[i + 1] = i; b[i + 1] = c(i, n);
}
}
for (int i = 1; i <= n / 2; ++i) {
printf ("%d %d\n", a[i], b[i]);
}
}
return 0;
}