Автор задачі: | Андрій Холод (Connect) |
Підготував: | Андрій Холод (Connect) |
Розбір: | Андрій Холод (Connect) |
Ідея
Потрібно розмістити на полі n \times m змійку максимальної довжини, яка утворює цикл (щоб рухатись нескінченно). При цьому дві сусідні клітинки змійки не можуть вказувати одна на одну.
Змійка має утворювати замкнений шлях, тому наша мета — побудувати цикл, що покриває якомога більше клітинок.
Ключове спостереження
Якщо хоча б одна зі сторін парна, можна покрити все поле (n \cdot m клітинок). Якщо обидві сторони непарні, максимум — n \cdot m - 1.
Розглянемо три випадки.
Випадок 1: парне
Будуємо зиґзаґ, що проходить через кожну клітинку рівно один раз і замикається в цикл:
Лівий стовпець (j = 0): змійка йде вниз від рядка до рядка n-1.
Нижній рядок (i = n-1): змійка йде вправо від стовпця до стовпця m-1.
Останній стовпець (j = m-1): змійка повертає вгору.
Внутрішні стовпці чергуються: непарні стовпці йдуть вгору, парні — вниз, з'єднуючись поворотами.
Довжина — n \cdot m.
Випадок 2: парне, непарне
Будуємо розв'язок для поля m \times n за Випадком 1 (бо парне, і воно стає кількістю стовпців), а потім транспонуємо сітку, замінюючи напрямки: U \leftrightarrow L, D \leftrightarrow R.
Довжина — n \cdot m.
Випадок 3: і обидва непарні
Покрити все поле циклом не вдасться (можна показати паритетним аргументом). Проте можна покрити n \cdot m - 1 клітинок:
Будуємо цикл для підполя n \times (m-1) за Випадком 1 (бо m-1 парне).
Розширюємо цикл в останній стовпець: беремо пари рядків і "витягуємо" змійку вправо, додаючи два повороти. Одна клітинка залишається непокритою.
Довжина — n \cdot m - 1.
Чому заборона розвороту виконується?
Побудований цикл завжди має довжину , тому кожна клітинка вказує "вперед" по циклу, і ситуація, коли дві сусідні клітинки вказують одна на одну, не виникає.
Асимптотика
Побудова сітки виконується за один прохід по всіх клітинках.
Отже маємо O(n \cdot m).
#include <bits/stdc++.h>
using namespace std;
vector<string> buildEvenCols(int n, int m) {
vector<string> g(n, string(m, '.'));
for (int i = 0; i < n - 1; i++) g[i][0] = 'D';
g[n - 1][0] = 'R';
for (int j = 1; j < m - 1; j++) g[n - 1][j] = 'R';
g[n - 1][m - 1] = 'U';
for (int j = 1; j < m; j++) {
if (j % 2 == 1) {
g[0][j] = 'L';
for (int i = 1; i <= n - 2; i++) g[i][j] = 'U';
} else {
g[0][j] = 'D';
for (int i = 1; i <= n - 3; i++) g[i][j] = 'D';
g[n - 2][j] = 'L';
}
}
return g;
}
vector<string> buildEvenRows(int n, int m) {
vector<string> t = buildEvenCols(m, n);
vector<string> g(n, string(m, '.'));
auto swapDir = [](char c) -> char {
switch (c) {
case 'U': return 'L';
case 'D': return 'R';
case 'L': return 'U';
case 'R': return 'D';
default: return c;
}
};
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
g[i][j] = swapDir(t[j][i]);
return g;
}
vector<string> buildOddOdd(int n, int m) {
vector<string> sub = buildEvenCols(n, m - 1);
vector<string> g(n, string(m, '.'));
for (int i = 0; i < n; i++)
for (int j = 0; j < m - 1; j++)
g[i][j] = sub[i][j];
for (int i = 1; i <= n - 2; i += 2) {
g[i + 1][m - 2] = 'R';
g[i + 1][m - 1] = 'U';
g[i ][m - 1] = 'L';
}
return g;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<string> g;
int len;
if (m % 2 == 0) {
g = buildEvenCols(n, m);
len = n * m;
} else if (n % 2 == 0) {
g = buildEvenRows(n, m);
len = n * m;
} else {
g = buildOddOdd(n, m);
len = n * m - 1;
}
cout << len << "\n";
for (auto& row : g) cout << row << "\n";
return 0;
}