#pragma GCC optimize("O3,unroll-loops") #pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt") #include #include #include #include #include #include using namespace std; const int MAX_SUM = 60000; bool is_sq_arr[MAX_SUM + 5]; int N; int W[105]; int Dist[105][105]; vector get_tree_path(int a, int b) { vector path; if (a < b) { for (int k = a; k < b; ++k) path.push_back(k); } else { for (int k = a - 1; k >= b; --k) path.push_back(k); } return path; } inline int get_shortcut_id(int x) { if (x == 2) return 1; return N + x - 3; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); auto start_time = chrono::steady_clock::now(); for (int i = 0; i * i <= MAX_SUM; ++i) { is_sq_arr[i * i] = true; } if (!(cin >> N)) return 0; if (N == 2) { cout << 1 << "\n"; cout << 1 << " " << 2 << " " << 1 << "\n"; cout << 1 << " " << 1 << "\n"; return 0; } for (int i = 1; i <= N; ++i) { for (int j = 1; j <= N; ++j) { Dist[i][j] = abs((i - 1) * (i - 1) - (j - 1) * (j - 1)); } } vector evens; for (int i = 2; i <= 200; i += 2) { evens.push_back(i); } mt19937 rng(1337); shuffle(evens.begin(), evens.end(), rng); for (int i = 3; i <= N; ++i) { W[i] = evens[i - 3]; } W[2] = 1; vector unused_evens; for (int i = N - 2; i < (int)evens.size(); ++i) { unused_evens.push_back(evens[i]); } auto get_time = [&]() { auto now = chrono::steady_clock::now(); return chrono::duration_cast(now - start_time).count(); }; auto calc_bad = [&]() { int bad = 0; for (int u = 2; u <= N; ++u) { for (int v = u + 1; v <= N; ++v) { if (is_sq_arr[Dist[u][v]]) continue; bool ok = false; for (int x = 2; x < v; ++x) { int max_ux = (u > x) ? u : x; int sum1 = Dist[u][x] + W[x]; for (int y = max_ux + 1; y <= N; ++y) { if (is_sq_arr[sum1 + W[y] + Dist[y][v]]) { ok = true; break; } } if (ok) break; } if (!ok) bad++; } } return bad; }; int current_bad = calc_bad(); int stuck_counter = 0; while (get_time() < 1800) { if (current_bad == 0) break; int type = rng() % 2; int idx1 = 3 + (rng() % (N - 2)); int old_w = W[idx1]; int u_idx = -1; int old_unused = -1; int idx2 = -1; if (type == 0 && !unused_evens.empty()) { u_idx = rng() % unused_evens.size(); old_unused = unused_evens[u_idx]; W[idx1] = old_unused; unused_evens[u_idx] = old_w; } else { idx2 = 3 + (rng() % (N - 2)); swap(W[idx1], W[idx2]); } int new_bad = 0; bool early_reject = false; for (int u = 2; u <= N; ++u) { for (int v = u + 1; v <= N; ++v) { if (is_sq_arr[Dist[u][v]]) continue; bool ok = false; for (int x = 2; x < v; ++x) { int max_ux = (u > x) ? u : x; int sum1 = Dist[u][x] + W[x]; for (int y = max_ux + 1; y <= N; ++y) { if (is_sq_arr[sum1 + W[y] + Dist[y][v]]) { ok = true; break; } } if (ok) break; } if (!ok) { new_bad++; if (new_bad > current_bad) { early_reject = true; break; } } } if (early_reject) break; } if (!early_reject && new_bad <= current_bad) { if (new_bad < current_bad) stuck_counter = 0; else stuck_counter++; current_bad = new_bad; } else { if (type == 0 && !unused_evens.empty()) { W[idx1] = old_w; unused_evens[u_idx] = old_unused; } else { swap(W[idx1], W[idx2]); } stuck_counter++; } if (stuck_counter > 5000) { shuffle(evens.begin(), evens.end(), rng); for (int i = 3; i <= N; ++i) W[i] = evens[i - 3]; unused_evens.clear(); for (int i = N - 2; i < (int)evens.size(); ++i) unused_evens.push_back(evens[i]); current_bad = calc_bad(); stuck_counter = 0; } } int M = 2 * N - 3; cout << M << "\n"; for (int i = 1; i < N; ++i) { cout << i << " " << i + 1 << " " << 2 * i - 1 << "\n"; } for (int i = 3; i <= N; ++i) { cout << 1 << " " << i << " " << W[i] << "\n"; } for (int u = 1; u <= N; ++u) { for (int v = u + 1; v <= N; ++v) { if (u == 1 || is_sq_arr[Dist[u][v]]) { vector path = get_tree_path(u, v); cout << path.size(); for (int e : path) cout << " " << e; cout << "\n"; continue; } bool printed = false; for (int x = 2; x < v && !printed; ++x) { int max_ux = (u > x) ? u : x; int sum1 = Dist[u][x] + W[x]; for (int y = max_ux + 1; y <= N && !printed; ++y) { if (is_sq_arr[sum1 + W[y] + Dist[y][v]]) { vector path; vector p1 = get_tree_path(u, x); path.insert(path.end(), p1.begin(), p1.end()); path.push_back(get_shortcut_id(x)); path.push_back(get_shortcut_id(y)); vector p2 = get_tree_path(y, v); path.insert(path.end(), p2.begin(), p2.end()); cout << path.size(); for (int e : path) cout << " " << e; cout << "\n"; printed = true; } } } } } return 0; }