Будинок#764

Будинок (Розбір)

Оголосимо двовимірний масив , в якому зберігатимемо інформацію про радіоактивне забруднення ділянки. Нехай mas[i][j] = 1, якщо клітинка заражена, і mas[i][j] = 0 в іншому випадку.

Далі перетворимо масив так, щоб mas[i][j] містило кількість радіоактивних клітинок у прямокутнику з кутами та . Це можна зробити за допомогою подвійного циклу по та . Припустимо, що значення mas[x][y] вже перераховані для всіх 1 \le x \le i, 1 \le y \le j, крім mas[i][j]. Тоді виконується наступна формула:

mas[i][j] = mas[i][j] + mas[i – 1][j] + mas[i][j - 1] - mas[i - 1][j - 1]

Після цього переберемо всі можливі позиції лівого верхнього кута будинку , де 1 \le i \le m - a + 1, 1 \le j \le n - b + 1, і перевіримо, чи є у відповідному прямокутнику хоча б одна радіоактивна клітинка.

Будинок можна побудувати (тобто вибраний прямокутник не містить радіоактивних клітинок), якщо значення виразу

mas[i + a - 1][j + b - 1] + mas[i - 1][j - 1] - mas[i - 1][j + b - 1] - mas[i + a - 1][j - 1]

дорівнює нулю.

Приклад

Розглянемо другий тест. Ліворуч показано вміст масиву після читання вхідних даних, а праворуч – значення елементів цього масиву після перерахунку.

Будинок розміром на можна розмістити лише в одному місці – з лівим верхнім кутом у позиції (i, j) = (3, 2) (нумерація позицій починається з ). Справді, маємо:

mas[4][3] + mas[2][1] - mas[4][1] - mas[2][3] = 4 + 1 - 2 - 3 = 0

Реалізація алгоритму

Оголосимо двовимірний масив . У змінній підраховуватимемо кількість способів розташування будинку.

#define MAX 5001
int mas[MAX][MAX], res;

Читаємо вхідні дані.

scanf("%d %d %d %d %d",&m,&n,&a,&b,&k);
memset(mas,0,sizeof(mas));

for (res = i = 0; i < k; i++)
{
  scanf("%d %d",&x,&y);
  mas[x][y] = 1;
}

Перерахуємо елементи масиву так, щоб mas[i][j] містило кількість радіоактивних клітинок у прямокутнику з кутами та .

for (i = 1; i <= m; i++)
for (j = 1; j <= n; j++)
  mas[i][j] = mas[i][j] + mas[i-1][j] + mas[i][j-1] - mas[i-1][j-1];

Перебираємо всі можливі координати лівого верхнього кута будинку і перевіряємо, чи є хоча б одна радіоактивна клітинка на ділянці, що відповідає будинку. Якщо таких клітинок немає, то в цьому місці можна побудувати будинок. У цьому випадку збільшуємо значення змінної на .

for(i = 1; i <= m - a + 1; i++)
for(j = 1; j <= n - b + 1; j++)
  if (mas[i+a-1][j+b-1] + mas[i-1][j-1] – mas[i-1][j+b-1] - mas[i+a-1][j-1] == 0) res++;

Виводимо відповідь.

printf("%d\n",res);

Реалізація на Java

import java.util.*;

public class Main
{
  static int mas[][];
  
  public static void main(String[] args)
  {
    Scanner con = new Scanner(System.in);
    int m = con.nextInt();
    int n = con.nextInt();
    int a = con.nextInt();
    int b = con.nextInt();
    int k = con.nextInt();
    
    mas = new int[m+1][n+1];
    int res = 0;
    for(int i = 0; i < k; i++)
    {
      int x = con.nextInt();
      int y = con.nextInt();
      mas[x][y] = 1;
    }
    
    for(int i = 1; i <= m; i++)
    for(int j = 1; j <= n; j++)
      mas[i][j] = mas[i][j] + mas[i-1][j] + mas[i][j-1] - mas[i-1][j-1];

    for(int i = 1; i <= m - a + 1; i++)
    for(int j = 1; j <= n - b + 1; j++)
      if (mas[i+a-1][j+b-1] + mas[i-1][j-1] - mas[i-1][j+b-1] - mas[i+a-1][j-1] == 0) res++;
    
    System.out.println(res);
    con.close();
  }
}