Problem Description
给出 n×nn \times nn×n 的矩阵,初始为 n×nn \times nn×n 个单位正方形,现在你能进行任意次以下操作:
合并任意 k×kk \times kk×k 的正方形区域(2≤k≤n2 \le k \le n2≤k≤n),并且区域中都要为正方形且正方形的个数小于等于 505050 。
Input
输入一个整数 nnn (1≤n≤10001 \le n \le 10001≤n≤1000) ,表示正方形的边长。
Output
输出一个整数 mmm (0≤m≤1060 \le m \le 10^60≤m≤106),表示操作次数。
接下来 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 n1≤x≤n,1≤y≤n,1≤k≤n),表示左上角所在的行号和列号,正方形的长度。
Solution
首先,对于 n≤7n \le 7n≤7 的正方形,我们可以直接合并。
-
对于 n%m≡0n \% m \equiv 0n%m≡0(2≤m≤72 \le m \le 72≤m≤7) ,我们可以进行简单地联想就能想到,可以将 nnn 分割成 m×mm \times mm×m 个 nm×nm\frac{n}{m} \times \frac{n}{m}mn×mn 区域,然后对于每个 nm×nm\frac{n}{m} \times \frac{n}{m}mn×mn 的 正方形区域进行操作。
-
而对于 n%m≢0n \% m \not\equiv 0n%m≡0(2≤m≤72 \le m \le 72≤m≤7) ,那么我们就可以将 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(n2logn)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;
}