1 条题解
-
0
简单构造。
图建出来是基环树森林。树的部分直接造必胜骰子即可,只要考虑环的情况。下文默认图是一个环,方便起见在反图上构造必败的情况。
首先 的情况下必定无解。以 为例,观察样例构造:
$$\begin{matrix} 1&8&11&14\\ 2&5&12&15\\ 3&6&9&16\\ 4&7&10&13\\ \end{matrix}$$这给我们一个重要思路:一列一列构造,保证后面的列中的数比前面大。这样在相邻两个骰子的比较中,我们只关心对应位置的数的大小关系了。
将其转化为 矩阵,设 ,其中 。则能得到:
$$\begin{matrix} 0&1&1&1\\ 1&0&1&1\\ 1&1&0&1\\ 1&1&1&0\\ \end{matrix}$$考虑一个 合法的充要条件:
- 对于任意一行, 的个数 ,也即满足必败。
- 对于任意一列,其不能全 或全 ,也即可以构造一个合法的 。
发现限制极松。具体地,让每列有尽可能多的 是不劣的。因此让每列只有一个 。按如下方式轮换构造即可:
$$\begin{matrix} 0&1&1&1&0&1&1&1&0&1&\cdots\\ 1&0&1&1&1&0&1&1&1&0&\cdots\\ 1&1&0&1&1&1&0&1&1&1&\cdots\\ 1&1&1&0&1&1&1&0&1&1&\cdots\\ \end{matrix}$$在该构造下,唯一一个反例是 的情况:
$$\begin{matrix} \color{red}{0}&\color{red}{1}&\color{red}{1}&\color{red}{0}&\\ 1&0&1&1&\\ 1&1&0&1&\\ \end{matrix}$$至于为什么是唯一的反例?考虑反例的出现条件:存在一行 个数大于 个数。考虑到两个 间会间隔 个 ,只有 的情况会出现不合法。
如何解决?事实上样例给出了一组 的解,套用即可。时间复杂度 。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN = 2e2 + 10; int n, m, a[MAXN], d[MAXN], ans[MAXN][MAXN], tot; vector<int> g[MAXN]; void dfs(int u) { for (int v : g[u]) { for (int i = 0; i < m; i++) ans[v][i] = ++tot; dfs(v); } } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%d", &a[i]), d[a[i]]++; queue<int> q; for (int i = 1; i <= n; i++) if (!d[i]) q.emplace(i); for (; !q.empty(); q.pop()) if (!--d[a[q.front()]]) q.emplace(a[q.front()]); for (int i = 1; i <= n; i++) if (!d[i]) g[a[i]].emplace_back(i); for (int i = 1; i <= n; i++) { if (d[i] <= 0) continue; vector<int> tmp; for (int u = i; d[u] > 0; tmp.emplace_back(u), d[u] = -1, u = a[u]); if (tmp.size() <= 2) return puts("0"), 0; if (tmp.size() == 3 && m == 4) { ans[tmp[0]][0] = ++tot, ans[tmp[1]][0] = ++tot, ans[tmp[0]][1] = ++tot, ans[tmp[2]][0] = ++tot; ans[tmp[2]][1] = ++tot, ans[tmp[2]][2] = ++tot, ans[tmp[1]][1] = ++tot, ans[tmp[1]][2] = ++tot; ans[tmp[1]][3] = ++tot, ans[tmp[0]][2] = ++tot, ans[tmp[0]][3] = ++tot, ans[tmp[2]][3] = ++tot; continue; } reverse(tmp.begin(), tmp.end()); for (int i = 0; i < m; i++) { for (int j = 0; j < tmp.size(); j++) { ans[tmp[(i + j) % tmp.size()]][i] = ++tot; } } } for (int i = 1; i <= n; i++) if (d[i] < 0) dfs(i); for (int i = 1; i <= n; i++) { for (int j = 0; j < m; j++) printf("%d ", ans[i][j]); } }
- 1
信息
- ID
- 2951
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 10
- 标签
- 递交数
- 4
- 已通过
- 1
- 上传者