The Lazy Cow
Pista 1
Si el rango de valores a los que Bessie puede moverse formara un cuadrado en vez de este diamante, podríamos aplicar sumas de prefijos normales.
Pista 2
¿Qué transformación llevaría un diamante a un cuadrado?
Solución
Explicación
Aplicamos una rotación de 45 grados sobre la grilla como sigue. Nuestro objetivo es que, en vez de un diamante como en el enunciado, las celdas a las que Bessie puede caminar formen un cuadrado.
| 0 | 0 | 50 | 0 | 0 | |||||
| 0 | 14 | 5 | 0 | ||||||
| 0 | 99 | 3 | 25 | 0 | |||||
| 8 | 10 | 2 | 6 | ||||||
| 10 | 7 | 1 | 7 | 17 | |||||
| 0 | 5 | 2 | 21 | ||||||
| 0 | 78 | 23 | 80 | 0 | |||||
| 0 | 1 | 11 | 0 | ||||||
| 0 | 0 | 9 | 0 | 0 | |||||
Si simplemente apretamos todas las diagonales en filas, se crea esta estructura extraña tipo ladrillo. Esto no tiene sentido, porque hay medias distancias. ¿Cómo se pone siquiera esto en un arreglo 2D? Para resolver el problema de las medias distancias, expandimos la grilla por un factor de 2, insertando ceros como relleno. Notemos que agregamos ceros porque no pueden afectar la suma final.
| 0 | 0 | 0 | 0 | 50 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 14 | 0 | 5 | 0 | 0 | 0 |
| 0 | 0 | 99 | 0 | 3 | 0 | 25 | 0 | 0 |
| 0 | 8 | 0 | 10 | 0 | 2 | 0 | 6 | 0 |
| 10 | 0 | 7 | 0 | 1 (B) | 0 | 7 | 0 | 17 |
| 0 | 0 | 0 | 5 | 0 | 2 | 0 | 21 | 0 |
| 0 | 0 | 78 | 0 | 23 | 0 | 80 | 0 | 0 |
| 0 | 0 | 0 | 1 | 0 | 11 | 0 | 0 | 0 |
| 0 | 0 | 0 | 0 | 9 | 0 | 0 | 0 | 0 |
Para demostrar lo que logramos, ahora miremos las celdas que Bessie (B) puede alcanzar cuando K = 2, la situación exacta del enunciado.
| 99 | 0 | 3 | 0 | 25 |
| 0 | 10 | 0 | 2 | 0 |
| 7 | 0 | 1 (B) | 0 | 7 |
| 0 | 5 | 0 | 2 | 0 |
| 78 | 0 | 23 | 0 | 80 |
Este rango ahora es un cuadrado, ¡lo que nos da muchas más posibilidades!
Para calcular la suma de los números en estos cuadrados, que ahora tienen forma de cuadrados, podemos usar sumas de prefijos 2D para calcular la suma de cada cuadrado en tiempo constante. Así, podemos hacer fuerza bruta sobre todos los cuadrados en los que Bessie puede estar y tomar la suma máxima.
Implementación
Complejidad temporal
#include <fstream>
#include <iostream>
#include <vector>
using std::endl;
using std::max;
using std::min;
using std::vector;
int main() {
std::ifstream read("lazy.in");
int n;
int k;
read >> n >> k;
// la longitud del lado necesaria para acomodar la rotación de 45 grados
int new_n = 2 * n - 1;
// -1 indica ubicaciones inválidas
vector<vector<int>> field(new_n, vector<int>(new_n, -1));
// leemos la entrada y la guardamos rotada 45 grados
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) { read >> field[i + j][n - i + j - 1]; }
}
vector<vector<int>> prefix(new_n + 1, vector<int>(new_n + 1));
for (int i = 0; i < new_n; i++) {
for (int j = 0; j < new_n; j++) {
// evitar incluir -1s en la suma de prefijos
int val = std::max(field[i][j], 0);
prefix[i + 1][j + 1] =
(val + prefix[i + 1][j] + prefix[i][j + 1] - prefix[i][j]);
}
}
int most_grass = 0;
for (int i = 0; i < new_n; i++) {
for (int j = 0; j < new_n; j++) {
if (field[i][j] == -1) {
continue; // no empezar en ubicaciones inválidas
}
int sr = max(i - k, 0), er = min(i + k, new_n - 1);
int sc = max(j - k, 0), ec = min(j + k, new_n - 1);
most_grass = max(most_grass, prefix[er + 1][ec + 1] - prefix[er + 1][sc] -
prefix[sr][ec + 1] + prefix[sr][sc]);
}
}
std::ofstream("lazy.out") << most_grass << endl;
}import java.io.*;
import java.util.*;
public class Lazy {
public static void main(String[] args) throws IOException {
Kattio io = new Kattio("lazy");
int n = io.nextInt();
int k = io.nextInt();
// la longitud del lado necesaria para acomodar la rotación de 45 grados
int newN = 2 * n - 1;
int[][] field = new int[newN][newN];
for (int r = 0; r < newN; r++) {
Arrays.fill(field[r], -1); // -1 indica ubicaciones inválidas
}
// leemos la entrada y la guardamos rotada 45 grados
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) { field[i + j][n - i + j - 1] = io.nextInt(); }
}
int[][] prefix = new int[newN + 1][newN + 1];
for (int i = 0; i < newN; i++) {
for (int j = 0; j < newN; j++) {
// evitar incluir -1s en la suma de prefijos
int val = Math.max(field[i][j], 0);
prefix[i + 1][j + 1] =
(val + prefix[i + 1][j] + prefix[i][j + 1] - prefix[i][j]);
}
}
int mostGrass = 0;
for (int i = 0; i < newN; i++) {
for (int j = 0; j < newN; j++) {
if (field[i][j] == -1) {
continue; // no empezar en ubicaciones inválidas
}
int sr = Math.max(i - k, 0), er = Math.min(i + k, newN - 1);
int sc = Math.max(j - k, 0), ec = Math.min(j + k, newN - 1);
mostGrass =
Math.max(mostGrass, prefix[er + 1][ec + 1] - prefix[er + 1][sc] -
prefix[sr][ec + 1] + prefix[sr][sc]);
}
}
io.println(mostGrass);
io.close();
}
// CodeSnip{Kattio}
}import sys
sys.stdin = open("lazy.in", "r")
n, k = map(int, input().split())
# la longitud del lado necesaria para acomodar la rotación de 45 grados
new_n = 2 * n - 1
field = [[-1] * new_n for _ in range(new_n)] # -1 indica ubicaciones inválidas
# leemos la entrada y la guardamos rotada 45 grados
for i in range(n):
for j, x in enumerate(map(int, input().split())):
field[i + j][n - i + j - 1] = x
prefix = [[0] * (new_n + 1) for _ in range(new_n + 1)]
for i in range(new_n):
for j in range(new_n):
val = max(field[i][j], 0) # evitar incluir -1s en la suma de prefijos
prefix[i + 1][j + 1] = val + prefix[i + 1][j] + prefix[i][j + 1] - prefix[i][j]
most_grass = 0
for i in range(new_n):
for j in range(new_n):
if field[i][j] == -1:
continue # no empezar en ubicaciones inválidas
sr = max(i - k, 0)
er = min(i + k, new_n - 1)
sc = max(j - k, 0)
ec = min(j + k, new_n - 1)
most_grass = max(
most_grass,
prefix[er + 1][ec + 1]
- prefix[er + 1][sc]
- prefix[sr][ec + 1]
+ prefix[sr][sc],
)
print(most_grass, file=open("lazy.out", "w"))