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$ 种情况:

  1. $k = 0$,那我们将 $c(i)$ 与 $i$ 进行配对,总和为 $\sum_{i=0}^{n/2-1} c(i) \& i = 0$
  2. $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$,
  3. $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;
} 
posted @ 2022-01-28 12:02  wangzhongyuan  阅读(2)  评论(0编辑  收藏  举报  来源