Codeforces Round #768 (Div. 2) C. And Matching (思维,分类讨论)

C. And Matching

https://codeforces.com/contest/1631/problem/C

在这里插入图片描述
①我们首先可以想到 k = 0 k=0 k=0 的情况,那就是对称的构造,也就是 ( i , n − i − 1 ) (i, n - i - 1) (i,ni1) 这么去构造。

②那么若 k ≠ 0 k \neq 0 k=0 时,我们就想,是否我们可以首先使得一个“对子”直接值为 k k k ,其余的都为 0 0 0 呢。那么如果要让一对值直接为 k k k ,那就让 k k k 直接去 & \& & 上一个全 1 1 1 的数就好了,也就是 n − 1 n-1 n1 ,然后我们发现这样的话 k k k 是不可以为 n − 1 n-1 n1 的,那么我们就先讨论 k ≠ n − 1 k \neq n-1 k=n1 的情况。让 k k k n − 1 n-1 n1 成一对之后,我们希望其它对都是 0 0 0 ,那么我思考这样操作( k k k n − 1 n-1 n1 配对)在①的构造方式上发生了哪些破坏呢,实际上就是只破坏了 ( 0 , n − 1 ) , ( k , n − 1 − k ) (0,n-1),(k,n-1-k) (0,n1),(k,n1k) 这个两个对,那么我们显然可以发现,让 k k k n − 1 n-1 n1 配对后,让 0 0 0 n − 1 − k n-1-k n1k 配对就完事了,其它的都保持原构造,这样全局的值就为 k k k 了。

③那么我们现在就考虑当 k = n − 1 k=n-1 k=n1 时的构造方式,那么我们往简单了想,能否构造个 n − 2 n-2 n2 1 1 1 出来,我们发现是可以的,我们可以形成 ( n − 1 , n − 2 ) (n-1,n-2) (n1,n2) 以构造出 n − 2 n-2 n2 ,再由 ( 1 , n − 3 ) (1,n-3) (1,n3) 造出 1 1 1 ,被破坏的 0 0 0 2 2 2 组合成 ( 0 , 2 ) (0,2) (0,2) 形成 0 0 0 ,其余的构造如①一样,这样总和就为 n + 2 + 1 = n − 1 n+2 +1=n-1 n+2+1=n1 了,实际上就是在①的基础上,调整 ( 0 , n − 1 ) ( 1 , n − 2 ) ( 2 , n − 3 ) (0,n-1)(1,n-2)(2,n-3) (0,n1)(1,n2)(2,n3) 的顺序。当然,我们会发现这样的情况只使用于 n ≥ 4 n \geq 4 n4 ,而且我们发现当 n = 4 n = 4 n=4 时是无解的。至此我们就考虑完了所有情况。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N = 2e5 + 10;

int n, k, pa[N], pb[N];

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    int T;
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &n, &k);
        for (int i = 0; i <= (n - 1) / 2; ++i) {
            pa[i] = i; pb[i] = n - i - 1;
        }
        if (n == 4 && k == 3) {
            puts("-1");
        }
        else if (k == 0) {
            for (int i = 0; i <= (n - 1) / 2; ++i) {
                printf("%d %d\n", i, n - i - 1);
            }
        }
        else if (k < n - 1) {
            printf("0 %d\n", n - 1 - k);
            printf("%d %d\n", k, n - 1);
            for (int i = 0; i <= (n - 1) / 2; ++i) {
                if (i != 0 && i != k && i != n - 1 - k) {
                    printf("%d %d\n", i, n - 1 - i);
                }
            }
        }
        else {
            printf("%d %d\n", n - 1, n - 2);
            printf("2 0\n");
            printf("1 %d\n", n - 3);
            for (int i = 0; i <= (n - 1) / 2; ++i) {
                if (i != 0 && i != 1 && i != 2 && i != k && i != n - 1 - k) {
                    printf("%d %d\n", i , n - i - 1);
                }
            }
        }
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值