CF1631C And Matching

思路分析

首先我们设 c(i) 为在 i 的二进制表示下,按位取反的结果,

例如:c(50)=c((110010)2)=(001101)2=13

显然 c(i)=(n1)i

因为 c(i)i 按位取反的结果,所以 c(i)&i=0

回到原题,我们分 3 种情况:

  1. k=0,那我们将 c(i)i 进行配对,总和为 i=0n/21c(i)&i=0
  2. 1kn2,将 c(i)i 进行配对,考虑把 0,k,c(k),n1 提取出来,将 kn1 配,k&(n1)=k0c(k) 配,0&c(k)=0,故总和为 k
  3. k=n1,将 c(i)i 进行配对,考虑把 0,1,2,(n3),(n2),(n1) 提取出来,(n1)(n2) 配对,(n1)&(n2)=(n2)1(n3) 配对,由于 (n3) 是奇数,所以 1&(n3)=1,再将 02 配对,结果为 0,那么总和为 (n2)+1+0++0=(n1)

注意:在第 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 @   wangzhongyuan  阅读(4)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示