P9890 [ICPC2018 Qingdao R] Tournament
P9890 [ICPC2018 Qingdao R] Tournament
构造好题。
因为任意一组构造在
正向构造:
- 第一步:两两配对。因为编号可以任意排列,所以
2k - 1 和2k 匹配是字典序最小的。如果不是2 的倍数,则办不到。 - 第二步:若
1 和2k - 1 配对,则2 和2k 配对;反之若1 和2k 配对,则2 和2k - 1 配对。这相当于将2k - 1 和2k 看成一组,两组之间配对,总共可以贡献两轮。如果不是4 的倍数,则办不到。 - 以此类推,第
i 步会将第i - 1 步的大小为2 ^ {i - 1} 的结构两两匹配,形成大小为2 ^ i 的结构并贡献2 ^ {i - 1} 轮,要求2 ^ i\mid n 。
综上,设
反向构造:设
容易证明这样构造得到的是字典序最小解。
时间复杂度
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using pdi = pair<double, int>;
using pdd = pair<double, double>;
using ull = unsigned long long;
using LL = __int128_t;
#define ppc(x) __builtin_popcount(x)
#define clz(x) __builtin_clz(x)
bool Mbe;
// ---------- templates above ----------
int n, k;
void solve(int T) {
cin >> n >> k;
if(k >= (n & -n)) cout << "Impossible\n";
else {
for(int i = 1; i <= k; i++) {
for(int a = 1; a <= n; a++) {
cout << ((a - 1) ^ i) + 1 << " ";
}
cout << "\n";
}
}
}
bool Med;
signed main() {
fprintf(stderr, "%.3lf MB\n", (&Mbe - &Med) / 1048576.0);
// ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
#ifdef ALEX_WEI
FILE* IN = freopen("1.in", "r", stdin);
FILE* OUT = freopen("1.out", "w", stdout);
#endif
int T = 1;
cin >> T;
while(T--) solve(T);
fprintf(stderr, "%.3lf ms\n", 1e3 * clock() / CLOCKS_PER_SEC);
return 0;
}
/*
g++ a.cpp -o a -std=c++14 -O2 -DALEX_WEI
*/