牛客多校2023 第4场 H Merge the squares!

文章介绍了一个解决n×n矩阵正方形合并问题的算法,通过递归和预处理减少操作次数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem Description

给出 n×nn \times nn×n 的矩阵,初始为 n×nn \times nn×n 个单位正方形,现在你能进行任意次以下操作:

合并任意 k×kk \times kk×k 的正方形区域(2≤k≤n2 \le k \le n2kn),并且区域中都要为正方形且正方形的个数小于等于 505050

Input

输入一个整数 nnn (1≤n≤10001 \le n \le 10001n1000) ,表示正方形的边长。

Output

输出一个整数 mmm (0≤m≤1060 \le m \le 10^60m106),表示操作次数。

接下来 mmm 行输出三个整数 x,y,zx,y,zx,y,z (1≤x≤n,1≤y≤n,1≤k≤n1 \le x \le n,1 \le y \le n,1 \le k \le n1xn,1yn,1kn),表示左上角所在的行号和列号,正方形的长度。

Solution

首先,对于 n≤7n \le 7n7 的正方形,我们可以直接合并。

  1. 对于 n%m≡0n \% m \equiv 0n%m0(2≤m≤72 \le m \le 72m7) ,我们可以进行简单地联想就能想到,可以将 nnn 分割成 m×mm \times mm×mnm×nm\frac{n}{m} \times \frac{n}{m}mn×mn 区域,然后对于每个 nm×nm\frac{n}{m} \times \frac{n}{m}mn×mn 的 正方形区域进行操作。

  2. 而对于 n%m≢0n \% m \not\equiv 0n%m0(2≤m≤72 \le m \le 72m7) ,那么我们就可以将 n×nn \times nn×n 可以拆分成 (a+ba+ba+b) ×\times× (a+ba+ba+b) 。

    • 那么我们就可以对于†\dagger {1,1,a1,1,a1,1,a},{a+1,a+1,ba+1,a+1,ba+1,a+1,b} 的正方形进行上述 111 操作,最终两个矩阵可以各自合并成一个正方形。
    • 而对于另外两个 a×ba \times ba×b 的矩形,我们可以每个对其中 c×cc \times cc×c(c=min(a,b)c=min(a,b)c=min(a,b)) 的正方形进行操作,而对于剩下的 (a%b)×b(a\%b) \times b(a%b)×b 或是 a×(b%a)a \times (b\%a)a×(b%a) 的矩形,我们递归此次操作即可,这个操作形如 gcdgcdgcd, 所以这是存在 a,ba,ba,b 使 a×ba\times ba×b 中的正方形小于等于 242424 ,寻找合适的 a,ba,ba,b ,我们可以直接O(n2log⁡n)O(n^2 \log n)O(n2logn)进行预处理。

如此我们只要对于 n×nn \times nn×n 的正方形进行以上递归操作,并用一个 vectorvectorvector 将答案存下即可。

†\dagger {x,y,kx,y,kx,y,k} 三元组表意对应 outputoutputoutput 中的 x,y,kx,y,kx,y,k

Code

#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
constexpr int N = 1e3 + 10;
int sigma[N], alpha[N];
//sigma判断是否能被 2-7 的数整除分割,并储存整除后的边长。
//alpha是当sigma[n]不存在时,储存(a+b)x(a+b)中的a。
vector<tuple<int, int, int>>ans;
void solve(int x, int y, int n, int m) {//x,y为左上角坐标,n,m为长宽
	if (n == m) {
		if (n <= 1)return;
		ans.emplace_back(x, y, n);
		if (n > 7) {
			if (sigma[n]) {
				int k = sigma[n];
				for (int i = x; i < x + n; i += k)
					for (int j = y; j <  y + m; j += k)
						solve(i, j, k, k);
			}
			else {
				int r1 = alpha[n], r2 = n - alpha[n];
				solve(x, y, r1, r1);
				solve(x + r1, y, r2, r1);
				solve(x, y + r1, r1, r2);
				solve(x + r1, y + r1, r2, r2);
			}
		}
	}
	else {
		if (n > m) {
			int len = n / m;
			for (int i = 0; i < len; i++)solve(x + i * m, y, m, m);
			if (n % m)solve(x + len * m, y, n % m, m);
		}
		else {
			int len = m / n;
			for (int i = 0; i < len; i++)solve(x, y + i * n, n, n);
			if (m % n)solve(x, y + len * n, n, m % n);
		}
	}
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int n;
	cin >> n;
	//预处理sigma
	for (int i = 2; i <= 7; i++)sigma[i] = i;
	for (int i = 8; i <= n; i++) {
		for (int j = 2; j <= 7; j++) {
			if (i % j == 0) {
				sigma[i] = i / j;
				break;
			}
		}
	}
	auto check = [&](int a, int b)->bool{//判断对于a,b分割成的正方形数是否小于等于24
		if (!b)return 0;
		int cnt = 1;
		while (b) {
			cnt += a / b;
			a = a % b;
			swap(a, b);
		}
		return cnt <= 24;
	};
	//预处理alpha
	for (int i = 8; i <= n; i++) {
		if (!sigma[i]) {
			for (int j = 0; j <= i / 2; j++) {
				if (check(i - j, j)) {
					alpha[i] = j;
					break;
				}
			}
		}
	}
	solve(1, 1, n, n);
	reverse(ans.begin(), ans.end());
	cout << ans.size() << endl;
	for (auto [x, y, k] : ans)cout << x << ' ' << y << ' ' << k << endl;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值