torus711 のアレ

主に競技プログラミングの問題について書きます.PC 以外だと数式が表示されないかもしれないです

HHKB プログラミングコンテスト 2020, B : Futon

問題概要

 高さ $H$, 幅 $W$ のグリッド状の盤面がある.グリッドの各セルは '.' または '#' である.
 縦に 2 つ隣接する '.' の箇所と,横に 2 つ隣接する '.' の箇所の数の和を求めよ.

制約

  • $2 \leq H, W \leq 100$

解法

 答えの総数は $O( HW )$ 個です.制約のサイズから,$\Theta( HW )$ 時間かけて数えても間に合います.よって,配置の左上になるセルと縦/横をすべて試して数えることができます.
 具体的には,セル $( i, j )$ をすべて舐めて,'.' であるようなセル $( i, j )$ に対して,セル $( i + 1, j )$ が存在してそこが '.' である場合(縦の配置)と,セル $( i, j + 1 )$ が存在してそこが '.' である場合(横の配置)の発生回数を数えればよいです.

コード

int main()
{
	IN( int, H, W );
	VS board( H );
	cin >> board;

	const auto ok = [&]( const int y, const int x )
	{
		return 0 <= y && y < H && 0 <= x && x < W && board[y][x] == '.';
	};

	int res = 0;
	REP( i, H )
	{
		REP( j, W )
		{
			res += ok( i, j ) && ok( i + 1, j );
			res += ok( i, j ) && ok( i, j + 1 );
		}
	}
	cout << res << endl;

	return 0;
}
main = do
	[ h, _ ] <- readInts
	board <- replicateM h getLine
	let
		trans = transpose board
	print $ sum ( map solve board ) + sum ( map solve trans )

solve [_] = 0
solve (c1:c2:rest)
	| c1 == '.' && c2 == '.' = 1 + solve (c2:rest)
	| otherwise = solve (c2:rest)