2018icpc青岛F . Tournament

发布时间 2023-04-01 16:15:22作者: zuotihenkuai

题目链接:https://codeforces.com/gym/104270/problem/F

题意:
有n个武士,编号1~n, 要进行k轮比赛,每轮比赛中所有武士都要出现,然后两名武士之间会发生决斗,并且一名武士在一轮比赛中只会与另外一名武士决斗,发生决斗的这两名武士,在其他轮比赛中,将不会再次决斗。
问能否构造出来符合题意的k轮比赛。

输入:
n, k分别表示武士的数目和比赛的轮数。
$ 1\leqslant n,k \leqslant 1000$

输出:
如果不可能构造出来符合题意的k轮比赛,输出"impossible"。
如果可以构造出来,输出k行,每行n个整数,对于第i行第j个数\(C_{ij}\)
其含义为,武士j将在第i轮与武士\(C_{ij}\)决斗。
如果有多种构造方法,输出字典序最小的。

Simple input:

2
3 1
4 3

Simple output:

Impossible
2 1 4 3
3 4 1 2
4 3 2 1

Solution:
要按字典序输出,很容易想到1, 2, 3, 4, 5 \(\dots\)n的情况。
但是每个武士不可能和自己决斗,可以两两交换变成2, 1, 4, 3\(\dots\)的情况。
然后列出来符合题意的字典序递增的几行:

1 2 3 4 5 6 7 8(这行是思维的起点,不合题意)
2 1 4 3 6 5 8 7
3 4 1 2 7 8 5 6
4 3 2 1 8 7 6 5
5 6 7 8 1 2 3 4
6 5 8 7 2 1 4 3
...

设1 2 3 4 5 6 7 8为第一行,行内每个元素分别是a[1][1]...a[1][n]可以发现
第二行是swap(a[1][1], a[1][2]), swap(a[1][3], a[1][4])...得到的
第三行是swap(a[2][1], a[2][4]), swap(a[2][2], a[2][3])...得到的
...
第五行是swap(a[4][1], a[4][8]), swap(a[4][2], a[4][7])...得到的
意思就是
直接看代码,更直观。

Code:

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
#define int LL

int lowbit(int x) {
	return x & (-x);
}

void solve(void) {
	int n, k; cin >> n >> k;
	if(k > lowbit(n) - 1) {
		cout << "Impossible\n";
		return;
	}
	int a[n + 1];
	for(int i = 1; i <= n; i ++) a[i] = i;
	for(int i = 1; i <= k; i ++) {
		int len = lowbit(i);
		for(int j = 1; j <= n; j += (len << 1)) {
			for(int kk = 0; kk < len; kk ++) {
				swap(a[j + kk], a[j + (len << 1) - kk - 1]);
			}
		}
		for(int j = 1; j <= n; j ++) cout << a[j] << ' ';
		cout << endl;
	}
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int t; cin >> t;
	while(t --) solve();
}