Codeforces 1044E - Grid Sort(构造)
114514 年前某培训机构讲的题。最近终于抽着星期天的空补掉了(
首先碰到这类题目我们可以套路化地想到归纳构造,具体来说我们考虑逐步将一行 / 一列上的元素归位,方便起见如果 \(n>m\) 就将最后一行复原成 \((n-1)m+1,(n-1)m+2,\cdots,nm\),否则将最后一列复原成 \(m,2m,3m,\cdots,nm\)。
如何复原一行呢?我们很明显可以想到这样的策略先两个数配对两两复原,如果 \(m\) 是奇数那就最后三个批量复原,即,我们先将 \((n-1)m+1\) 放到 \((1,1)\) 的位置,再将 \((n-1)m+2\) 放到 \((2,1)\) 的位置,然后绕一个大圈将它们绕到 \((n,1)\) 和 \((n,2)\),然后再对 \((n-1)m+3\) 和 \((n-1)m+4\) 做同样的操作即可。绕圈圈这一部分最无脑的办法是将包含 \((1,1),(2,1),(n,1),(n,2)\) 的四个格子的最小环找到然后不断绕直到 \((n,1),(n,2)\) 的位置,但这样 \(\sum |S|\) 是四方的。更优的办法是只绕 \(2\times 2\) 的环,这样 \(\sum |S|\) 就变成三方了,不加卡常通过此题的限制无压力。
注意到我们上面的归纳对于 \(n\le 3,m\le 3\) 是行不通的,而此题 \(n,m\) 下界刚好是 \(3\),因此我们还需要解决 \(n=3,m=3\) 的问题,这种情况想怎么做就怎么做,感觉上 DFS/BFS 都是可以的,时间复杂度 \(9!·9^2\),但是不知道为什么我的 DFS 要 4w 多步所以就写了 BFS。
跑得巨慢且写得巨垃圾的代码,真心不建议看:
const int MAXN = 20;
vector<vector<int> > ans;
int n, m, a[MAXN + 2][MAXN + 2], ought[MAXN + 2][MAXN + 2];
void rotate() {
static int tmp_a[MAXN + 2][MAXN + 2], tmp_ought[MAXN + 2][MAXN + 2];
memset(tmp_a, 0, sizeof(tmp_a)); memset(tmp_ought, 0, sizeof(tmp_ought));
for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++)
tmp_a[j][i] = a[i][j], tmp_ought[j][i] = ought[i][j];
swap(n, m);
memset(a, 0, sizeof(a)); memset(ought, 0, sizeof(ought));
for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++)
a[i][j] = tmp_a[i][j], ought[i][j] = tmp_ought[i][j];
}
void opt(vector<pii> vec) {
vector<int> A; for (pii p : vec) A.pb(a[p.fi][p.se]); ans.pb(A);
static int b[MAXN + 2][MAXN + 2];
for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) b[i][j] = a[i][j];
for (int i = 0; i < vec.size(); i++) b[vec[(i + 1) % vec.size()].fi][vec[(i + 1) % vec.size()].se] = a[vec[i].fi][vec[i].se];
for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) a[i][j] = b[i][j];
}
void work(int v, int x, int y) {
int nx = 0, ny = 0;
for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) if (a[i][j] == v) nx = i, ny = j;
while (nx > x) {
if (ny != m) opt(vector<pii>{mp(nx, ny), mp(nx - 1, ny), mp(nx - 1, ny + 1), mp(nx, ny + 1)});
else opt(vector<pii>{mp(nx, ny), mp(nx - 1, ny), mp(nx - 1, ny - 1), mp(nx, ny - 1)});
nx--;
}
while (nx < x) {
if (ny != m) opt(vector<pii>{mp(nx, ny), mp(nx + 1, ny), mp(nx + 1, ny + 1), mp(nx, ny + 1)});
else opt(vector<pii>{mp(nx, ny), mp(nx + 1, ny), mp(nx + 1, ny - 1), mp(nx, ny - 1)});
nx++;
}
while (ny > y) opt(vector<pii>{mp(nx, ny), mp(nx, ny - 1), mp(nx + 1, ny - 1), mp(nx + 1, ny)}), ny--;
}
namespace Three_Times_Three {
const int MAXC = 362880;
vector<int> CYC[12] = {
vector<int>{0, 1, 4, 3},
vector<int>{3, 4, 7, 6},
vector<int>{1, 2, 5, 4},
vector<int>{4, 5, 8, 7},
vector<int>{0, 1, 4, 7, 6, 3},
vector<int>{1, 2, 5, 8, 7, 4},
vector<int>{0, 1, 2, 5, 4, 3},
vector<int>{3, 4, 5, 8, 7, 6},
vector<int>{0, 1, 4, 5, 8, 7, 6, 3},
vector<int>{0, 1, 2, 5, 8, 7, 4, 3},
vector<int>{0, 1, 2, 5, 4, 7, 6, 3},
vector<int>{1, 2, 5, 8, 7, 6, 3, 4}
};
bool vis[MAXC + 5];
vector<vector<int> > pth[MAXC + 5];
int calc(vector<int> vec) {
int prd = 1, res = 0;
for (int i = 8; ~i; i--) {
int sum = 0;
for (int j = i + 1; j < 9; j++) sum += vec[j] < vec[i];
res += sum * prd; prd *= (9 - i);
}
return res;
}
void solve33() {
queue<vector<int> > q; vector<int> st, ed;
for (int i = 1; i <= 3; i++) for (int j = 1; j <= 3; j++) st.pb(a[i][j]), ed.pb(ought[i][j]);
q.push(st);
while (!q.empty()) {
vector<int> vec = q.front(); q.pop(); int ID = calc(vec);
if (vec == ed) {for (auto v : pth[ID]) ans.pb(v); break;}
for (int i = 0; i < 12; i++) {
vector<int> tmp = vec;
for (int j = 0; j < CYC[i].size(); j++) tmp[CYC[i][(j + 1) % CYC[i].size()]] = vec[CYC[i][j]];
int nID = calc(tmp);
if (!vis[nID]) {
pth[nID] = pth[ID]; vector<int> trs;
for (int x : CYC[i]) trs.pb(vec[x]);
pth[nID].pb(trs); vis[nID] = 1;
q.push(tmp);
}
}
}
}
} using namespace Three_Times_Three;
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++)
scanf("%d", &a[i][j]), ought[i][j] = (i - 1) * m + j;
while (n > 3 || m > 3) {
if (n < m) rotate();
auto deal2 = [&](int id) {
work(ought[n][id + 1], 1, 1); work(ought[n][id], 2, 1);
for (int i = 1; i <= n - 3; i++) opt(vector<pii>{mp(i, 1), mp(i + 1, 1), mp(i + 2, 1), mp(i + 2, 2), mp(i + 1, 2), mp(i, 2)});
opt(vector<pii>{mp(n - 2, 1), mp(n - 1, 1), mp(n - 1, 2), mp(n - 2, 2)});
for (int i = 1; i < id; i++) opt(vector<pii>{mp(n - 1, i), mp(n - 1, i + 1), mp(n - 1, i + 2), mp(n - 2, i + 2), mp(n - 2, i + 1), mp(n - 2, i)});
opt(vector<pii>{mp(n - 1, id), mp(n - 1, id + 1), mp(n, id + 1), mp(n, id)});
opt(vector<pii>{mp(n - 1, id), mp(n - 1, id + 1), mp(n, id + 1), mp(n, id)});
};
auto deal3 = [&](int id) {
work(ought[n][id + 2], 1, 1); work(ought[n][id + 1], 2, 1); work(ought[n][id], 3, 1);
for (int i = 1; i <= n - 4; i++) opt(vector<pii>{mp(i, 1), mp(i + 1, 1), mp(i + 2, 1), mp(i + 3, 1), mp(i + 3, 2), mp(i + 2, 2), mp(i + 1, 2), mp(i, 2)});
opt(vector<pii>{mp(n - 3, 1), mp(n - 2, 1), mp(n - 1, 1), mp(n - 1, 2), mp(n - 2, 2), mp(n - 3, 2)});
opt(vector<pii>{mp(n - 2, 1), mp(n - 1, 1), mp(n - 1, 2), mp(n - 1, 3), mp(n - 2, 3), mp(n - 2, 2)});
for (int i = 1; i < id; i++) opt(vector<pii>{mp(n - 1, i), mp(n - 1, i + 1), mp(n - 1, i + 2), mp(n - 1, i + 3), mp(n - 2, i + 3), mp(n - 2, i + 2), mp(n - 2, i + 1), mp(n - 2, i)});
opt(vector<pii>{mp(n - 1, id), mp(n - 1, id + 1), mp(n - 1, id + 2), mp(n, id + 2), mp(n, id + 1), mp(n, id)});
opt(vector<pii>{mp(n - 1, id), mp(n - 1, id + 1), mp(n - 1, id + 2), mp(n, id + 2), mp(n, id + 1), mp(n, id)});
opt(vector<pii>{mp(n - 1, id), mp(n - 1, id + 1), mp(n - 1, id + 2), mp(n, id + 2), mp(n, id + 1), mp(n, id)});
};
if (m % 2 == 0) {
for (int i = 1; i <= m; i += 2) deal2(i);
} else {
for (int i = 1; i <= m - 3; i += 2) deal2(i);
deal3(m - 2);
}
n--;
}
solve33();
printf("%d\n", (int)ans.size());
for (auto v : ans) {
printf("%d", (int)v.size());
for (int x : v) printf(" %d", x);
printf("\n");
}
return 0;
}
/*
4 4
9 5 8 11
2 13 7 4
15 1 3 6
10 16 12 14
*/