Codeforces 1044E - Grid Sort(构造)

Codeforces 题面传送门 & 洛谷题面传送门

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
*/
posted @ 2022-07-07 18:33  tzc_wk  阅读(31)  评论(0编辑  收藏  举报