Skip to content

USACO 2021 February Contest Bronze Division - Comfortable Cows#

Problem link: here

Solution Author: Stefan Dascalescu

Problem Solution#

The key observation for this problem is that the only cells that could be affected by the new cow are the cow itself, its four neighbors and the neighbors of those neighbors.

Source codes#

The source codes in C++ and Python can be seen below.

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int OFFSET = 10;        
int comfortableCount = 0;

bool occupied[1020][1020];
bool comfortable[1020][1020];

int dx[4] = {1, -1, 0, 0};
int dy[4] = {0, 0, 1, -1};

bool isComfortable(int x, int y) {
    if (!occupied[x][y]) {
        return 0;
    }
    int count = 0;
    for (int i = 0; i < 4; i++){
        int nx = x + dx[i];
        int ny = y + dy[i];
        if (occupied[nx][ny]) {
            count++;
        }
    }
    return (count == 3);
}

void updateCell(int x, int y) {
    if (x < 1 || x >= 1020 || y < 1 || y >= 1020 || occupied[x][y] == 0) {
        return;
    }
    if (!occupied[x][y]) {
        return;
    }

    bool wasComfortable = comfortable[x][y];
    bool nowComfortable = isComfortable(x, y);

    if (wasComfortable && !nowComfortable) {
        comfortable[x][y] = false;
        comfortableCount--;
    }
    else if (!wasComfortable && nowComfortable) {
        comfortable[x][y] = true;
        comfortableCount++;
    }
}

int main() {
    int n;
    cin >> n;

    for (int i = 0; i < n; i++){
        int a, b;
        cin >> a >> b;
        a += OFFSET;
        b += OFFSET;

        occupied[a][b] = true;

        vector<pair<int,int>> toCheck;
        toCheck.push_back({a, b});
        for (int j = 0; j < 4; j++){
            int nx = a + dx[j], ny = b + dy[j];
            toCheck.push_back({nx, ny});
            for (int k = 0; k < 4; k++){
                int nnx = nx + dx[k], nny = ny + dy[k];
                toCheck.push_back({nnx, nny});
            }
        }

        sort(toCheck.begin(), toCheck.end());
        toCheck.erase(unique(toCheck.begin(), toCheck.end()), toCheck.end());
        for (auto cell: toCheck){
            updateCell(cell.first, cell.second);
        }

        cout << comfortableCount << "\n";
    }
    return 0;
}
OFFSET = 10
SIZE = 1020
comfortableCount = 0
occupied = [[False] * SIZE for _ in range(SIZE)]
comfortable = [[False] * SIZE for _ in range(SIZE)]
dx = [1, -1, 0, 0]
dy = [0, 0, 1, -1]

def isComfortable(x, y):
    if not occupied[x][y]:
        return False
    count = 0
    for i in range(4):
        nx = x + dx[i]
        ny = y + dy[i]
        if occupied[nx][ny]:
            count += 1
    return count == 3

def updateCell(x, y):
    global comfortableCount
    if x < 1 or x >= SIZE or y < 1 or y >= SIZE or not occupied[x][y]:
        return
    wasComfortable = comfortable[x][y]
    nowComfortable = isComfortable(x, y)
    if wasComfortable and not nowComfortable:
        comfortable[x][y] = False
        comfortableCount -= 1
    elif not wasComfortable and nowComfortable:
        comfortable[x][y] = True
        comfortableCount += 1

n = int(input())
for _ in range(n):
    a, b = map(int, input().split())
    a += OFFSET
    b += OFFSET
    occupied[a][b] = True

    toCheck = []
    toCheck.append((a, b))
    for j in range(4):
        nx = a + dx[j]
        ny = b + dy[j]
        toCheck.append((nx, ny))
        for k in range(4):
            nnx = nx + dx[k]
            nny = ny + dy[k]
            toCheck.append((nnx, nny))
    toCheck = set(toCheck)
    for cell in toCheck:
        updateCell(cell[0], cell[1])
    print(comfortableCount)