Zonal Computing Olympiad 2013, 10 Nov 2012

Little Red Riding Hood is carrying a basket with berries through the forest to her grandmother's house.  The forest is arranged in the form of a square N × N grid of cells.  The top left corner cell, where Little Red Riding Hood starts her journey, is numbered (1,1) and the bottom right corner cell, where her grandmother lives, is numbered (N,N).  In each step, she can move either one position right or one position down.

The forest is full of dangerous wolves and she is looking for a safe path to reach her destination.  Little Red Riding Hood's fairy godmother has placed some special anti-wolf magical charms in some of the cells in the grid.  Each charm has a strength.  If the charm in cell (i,j) has strength k then its zone of influence is all the cells within k steps of (i,j); that is, all cells (i',j') such that |i - i'| + |j - j'| ≤ k.  A cell within the zone of influence of a charm is safe from wolves.  A safe path from (1,1) to (N,N) is one in which every cell along the path is safe.

Little Red Riding Hood is carrying a basket with berries. In each cell, she drops some berries while pushing her way through the thick forest.  However, sometimes she is also able to pick up fresh berries.  Each cell is labelled with an integer that indicates the net change in the number of berries in her basket on passing through the cell; that is, the number of berries she picks up in that cell minus the number of berries she drops.  You can assume that there are enough berries in her basket to start with so that the basket never becomes empty.

Little Red Riding Hood knows the positions and strengths of all the magic charms and is looking for a safe path along which the number of berries she has in the basket when she reaches her grandmother's house is maximized.

As an example consider the following grid:

3  3  2  4  3 
2  1 -1 -2  2  
-1  2  4  3 -3  
-2  2  3  2  1  
3 -1  2 -1  2  

Suppose there are 3 magic charms, at position (1,2) with strength 2, at position (4,5) with strength 2 and one at position (4,2) with strength 1.  The positions within the zone of influence of these three charms are indicated in the three grids below using X's.  

X  X  X  X  .         .  .  .  .  .         .  .  .  .  .
X  X  X  .  .         .  .  .  .  X         .  .  .  .  .
.  X  .  .  .         .  .  .  X  X         .  X  .  .  .
.  .  .  .  .         .  .  X  X  X         X  X  X  .  .
.  .  .  .  .         .  .  .  X  X         .  X  .  .  .

Putting these together, the cells that are under the zone of influence of at least one charm are marked with X below.

X  X  X  X  .
X  X  X  .  X
.  X  .  X  X
X  X  X  X  X
.  X  .  X  X

Here are two examples of safe paths in this grid, marked using Y's.  

Y  Y  X  X  .          Y  X  X  X  .
X  Y  X  .  X          Y  Y  X  .  X
.  Y  .  X  X          .  Y  .  X  X
X  Y  Y  Y  Y          X  Y  Y  Y  X
.  X  .  X  Y          .  X  .  Y  Y

Along the first path, she accumulates 19 berries while on the second path she collects 16 berries.  You can verify that among all safe paths, the maximum number of berries she can collect is 19. 

Your task is to help Little Red Riding Hood find out if there is at least one safe path and, if so, compute the maximum number of berries she can collect among all safe paths (which may be a negative number, in which case it is the minimum number of berries she will lose among all safe paths).

-----Input format-----
Line 1: Two space separated integers N and M, giving the dimension of the grid and the number of magic charms, respectively

Lines 2 to N+1: These N lines desribe the grid.  Line i+1 contains N space separated integers, describing the net change in berries in the N cells along row i of the grid.

Lines N+2 to N+M+1: These M lines describe the magic charms.  Each of these lines has 3 integers: the first two integers describe the position of the charm in the grid and the third integer describes its strength.

-----Output format-----
The first line of output must either consist of the word YES, if there are safe paths, or the word NO, if there are no safe paths. If the output on the first line is YES then the second line should contain a single integer giving the maximum number of berries Little Red Riding Hood can collect among all safe paths.  

-----Sample Input-----
5 3
3 3 2 4 3 
2 1 -1 -2 2  
-1 2 4 3 -3  
-2 2 3 2 1  
3 -1 2 -1 2  
1 2 2
4 5 2
4 2 1

-----Sample Output-----
YES
19

-----Test data-----
In all subtasks, you may assume that 2 ≤ N ≤ 500.  Each value on the grid is guaranteed to have absolute value not more than 1000. 
Let K denote the maximum strength among all the magic charms.
- Subtask 1 (30 marks) : 1 ≤ M ≤ 10, 1 ≤ K ≤ 1,000.
- Subtask 2 (70 marks) : 1 ≤ M ≤ 10,000, 1 ≤ K ≤ 10.

-----Live evaluation data-----
- Subtask 1: Testcases 0,1,2,3,4.
- Subtask 2: Testcases 5,6,7,8.

Difficulty: UNKNOWN_DIFFICULTY

Solutions:
import sys

def dist(a, b):
	return abs(a[0] - b[0]) + abs(a[1] - b[1])
(n, m) = map(int, input().split())
matrix = []
id_matrix = [[0 for i in range(n)] for i in range(n)]
for _ in range(n):
	matrix.append(list(map(int, input().split())))
charms = []
for _ in range(m):
	(x, y, lungh) = map(int, input().split())
	x -= 1
	y -= 1
	charms.append([x, y, lungh])
if m <= 10:
	for i in range(n):
		for j in range(n):
			flag = 0
			for charm in charms:
				if dist([i, j], charm[:2]) <= charm[2]:
					flag = 1
					break
			if flag == 0:
				matrix[i][j] = -float('Inf')
	for i in range(1, n):
		matrix[0][i] += matrix[0][i - 1]
		matrix[i][0] += matrix[i - 1][0]
	for i in range(1, n):
		for j in range(1, n):
			matrix[i][j] += max(matrix[i - 1][j], matrix[i][j - 1])
else:
	for charm in charms:
		for i in range(-charm[2], charm[2] + 1):
			appo = charm[2] - abs(i)
			for j in range(-appo, appo + 1):
				x = i + charm[0]
				y = j + charm[1]
				if x >= 0 and x < n and (y >= 0) and (y < n):
					id_matrix[x][y] = 1
	if id_matrix[0][0] == 0:
		matrix[0][0] = -float('Inf')
	for i in range(1, n):
		if id_matrix[0][i] == 0:
			matrix[0][i] = -float('Inf')
		else:
			matrix[0][i] += matrix[0][i - 1]
		if id_matrix[i][0] == 0:
			matrix[i][0] = -float('Inf')
		else:
			matrix[i][0] += matrix[i - 1][0]
	for i in range(1, n):
		for j in range(1, n):
			if id_matrix[i][j] == 0:
				matrix[i][j] = -float('Inf')
			else:
				matrix[i][j] += max(matrix[i - 1][j], matrix[i][j - 1])
if matrix[n - 1][n - 1] < -10 ** 10:
	print('NO')
else:
	print('YES')
	print(matrix[n - 1][n - 1])


def main():
	(n, m) = (int(x) for x in input().split())
	grid = [[int(x) for x in input().split()] for _ in range(n)]
	charms = [[int(x) for x in input().split()] for _ in range(m)]
	n_inf = -9999
	dp = [[n_inf] * n for _ in range(n)]
	for c in charms:
		c[0] -= 1
		c[1] -= 1
		x = max(0, c[0] - c[2])
		while x < n and x <= c[0] + c[2]:
			off = abs(x - c[0])
			y = max(0, c[1] - c[2] + off)
			while y < n and y <= c[1] + c[2] - off:
				dp[x][y] = grid[x][y]
				y += 1
			x += 1
	for x in range(1, n):
		if dp[x - 1][0] == n_inf:
			for x1 in range(x, n):
				dp[x1][0] = n_inf
			break
		dp[x][0] += dp[x - 1][0]
	for y in range(1, n):
		if dp[0][y - 1] == n_inf:
			for y1 in range(y, n):
				dp[0][y1] = n_inf
			break
		dp[0][y] += dp[0][y - 1]
	for x in range(1, n):
		for y in range(1, n):
			m = max(dp[x - 1][y], dp[x][y - 1])
			dp[x][y] = m + dp[x][y] if m != n_inf else n_inf
	if dp[-1][-1] != n_inf:
		print('YES')
		print(str(dp[-1][-1]))
	else:
		print('NO')
main()


(N, M) = map(int, input().split())
grid = [[int(i) for i in input().split()] for j in range(N)]
charms = [[*map(int, input().split())] for i in range(M)]
dp = [[None for n in range(N)] for m in range(N)]
dp[0][0] = grid[0][0]

def valid_square(coord, charms):
	for charm in charms:
		if abs(coord[0] + 1 - charm[0]) + abs(coord[1] + 1 - charm[1]) <= charm[2]:
			return True
	return False
for y in range(N):
	for x in range(N):
		if valid_square((y, x), charms):
			if y == 0:
				if dp[y][x - 1]:
					dp[y][x] = dp[y][x - 1] + grid[y][x]
			elif x == 0:
				if dp[y - 1][x]:
					dp[y][x] = dp[y - 1][x] + grid[y][x]
			elif dp[y - 1][x] or dp[y][x - 1]:
				dp[y][x] = grid[y][x] + max(dp[y][x - 1] or 0, dp[y - 1][x] or 0)
if dp[N - 1][N - 1]:
	print('YES')
	print(dp[N - 1][N - 1])
else:
	print('NO')


def findMax(safePath, relBerries, collectedBerries, cx, cy, n, ans):
	if cx == n - 1 and cy == n - 1:
		ans['reached'] = True
		collectedBerries += relBerries[cx][cy]
		ans['maxberries'] = max(ans['maxberries'], collectedBerries)
	else:
		if collectedBerries <= ans['prev'][cx][cy]:
			return
		else:
			ans['prev'][cx][cy] = collectedBerries
		if cx != n - 1 and safePath[cx + 1][cy] == 1:
			findMax(safePath, relBerries, collectedBerries + relBerries[cx][cy], cx + 1, cy, n, ans)
		if cy != n - 1 and safePath[cx][cy + 1] == 1:
			findMax(safePath, relBerries, collectedBerries + relBerries[cx][cy], cx, cy + 1, n, ans)
(n, m) = map(int, input().split())
relBerries = []
safePaths = []
for i in range(n):
	safePaths.append([0] * n)
for i in range(n):
	relBerries.append(list(map(int, input().split())))
for i in range(m):
	(x, y, s) = map(int, input().split())
	x -= 1
	y -= 1
	for j in range(0, s + 1):
		if x - j >= 0:
			safePaths[x - j][y] = 1
			for z in range(1, s - j + 1):
				if y + z < n:
					safePaths[x - j][y + z] = 1
				else:
					break
			for z in range(1, s - j + 1):
				if y - z >= 0:
					safePaths[x - j][y - z] = 1
				else:
					break
		if x + j < n and j != 0:
			safePaths[x + j][y] = 1
			for z in range(1, s - j + 1):
				if y + z < n:
					safePaths[x + j][y + z] = 1
				else:
					break
			for z in range(1, s - j + 1):
				if y - z >= 0:
					safePaths[x + j][y - z] = 1
				else:
					break
ans = {}
ans['maxberries'] = -100000000
ans['reached'] = False
ans['prev'] = []
for i in range(n):
	ans['prev'].append([-100000000] * n)
findMax(safePaths, relBerries, 0, 0, 0, n, ans)
if ans['reached']:
	print('YES')
	print(ans['maxberries'])
else:
	print('NO')


import collections

def solve(n, m, grid, charms):
	newGrid = [[[val, False] for val in row] for row in grid]
	for (x, y, k) in charms:
		newGrid[x][y][1] = True
		queue = collections.deque([(x, y, 0)])
		visited = set()
		visited.add((x, y))
		while queue:
			(currX, currY, cost) = queue.popleft()
			for (delX, delY) in [(-1, 0), (1, 0), (0, 1), (0, -1)]:
				(newX, newY) = (currX + delX, currY + delY)
				if 0 <= newX < n and 0 <= newY < n and ((newX, newY) not in visited) and (cost < k):
					newGrid[newX][newY][1] = True
					visited.add((newX, newY))
					if cost + 1 <= k:
						queue.append((newX, newY, cost + 1))
	NEG_INF = float('-inf')
	dp = [[NEG_INF if not newGrid[i][j][1] else newGrid[i][j][0] for j in range(n)] for i in range(n)]
	for i in range(n):
		for j in range(n):
			if i == 0 and j == 0:
				continue
			elif i == 0:
				dp[i][j] += dp[i][j - 1]
			elif j == 0:
				dp[i][j] += dp[i - 1][j]
			else:
				dp[i][j] += max(dp[i - 1][j], dp[i][j - 1])
	return (dp[n - 1][n - 1] != NEG_INF, dp[n - 1][n - 1])
[n, m] = list(map(int, input().strip().split()))
grid = []
for i in range(n):
	row = list(map(int, input().strip().split()))
	grid.append(row)
charms = []
for i in range(m):
	[x, y, k] = list(map(int, input().strip().split()))
	charms.append((x - 1, y - 1, k))
ans = solve(n, m, grid, charms)
if ans[0]:
	print('YES')
	print(ans[1])
else:
	print('NO')


ipnl = lambda n: [int(input()) for _ in range(n)]
inp = lambda : int(input())
ip = lambda : [int(w) for w in input().split()]
(n, m) = ip()
grid = []
for i in range(n):
	grid.append(ip())
mat = [[0 for i in range(n + 1)] for j in range(n + 1)]
for _ in range(m):
	(a, b, k) = ip()
	f = 0
	for j in range(b - k, b + k + 1):
		if 0 < j <= n:
			for i in range(a - f, a + f + 1):
				if 0 < i <= n:
					mat[i][j] = 1
		if j < b:
			f += 1
		else:
			f -= 1
for i in range(n + 1):
	mat[i][0] = -1
	mat[0][i] = -1
grid.insert(0, [float('-inf') for i in range(n)])
for i in range(len(grid)):
	grid[i].insert(0, float('-inf'))
for i in range(1, n + 1):
	for j in range(1, n + 1):
		if mat[i - 1][j] == 0 and mat[i][j - 1] == 0:
			mat[i][j] = 0
		else:
			(a, b) = (float('-inf'), float('-inf'))
			if mat[i - 1][j] != 0:
				a = grid[i - 1][j]
			if mat[i][j - 1] != 0:
				b = grid[i][j - 1]
			if not (i == 1 and j == 1):
				grid[i][j] += max(a, b)
if mat[-1][-1] == 0 or mat[1][1] == 0:
	print('NO')
else:
	print('YES')
	print(grid[-1][-1])


import numpy as np
(n, mC) = [int(i) for i in input().split()]
arr = np.array([[int(i) for i in input().split()] for j in range(n)])
charms = [[int(i) for i in input().split()] for j in range(mC)]
block = 1001
safeArr = np.full((n, n), block)
inBounds = lambda ind: 0 <= ind < n
for charm in charms:
	(x, y, stg) = charm
	x -= 1
	y -= 1
	maxWidth = stg * 2 + 1
	seqX = []
	seqY = []
	ct = x - stg
	for i in range(maxWidth):
		l = stg - abs(stg - i)
		seqX.extend([ct] * (l * 2 + 1))
		seqY.extend(list(range(y - l, y + l + 1)))
		ct += 1
	safeCoords = np.array(list(filter(lambda x: inBounds(x[0]) and inBounds(x[1]), zip(seqX, seqY))))
	finalCoords = (safeCoords[:, 0], safeCoords[:, 1])
	safeArr[finalCoords] = arr[finalCoords]
if safeArr[0, 0] == block or safeArr[-1, -1] == block:
	print('NO')
else:
	prevRow = safeArr[0].copy()
	for j in range(1, n):
		left = prevRow[j - 1]
		if prevRow[j] != block:
			if left == block:
				prevRow[j] = block
			else:
				prevRow[j] += left
	for i in range(1, n):
		thisRow = safeArr[i].copy()
		if thisRow[0] != block:
			if prevRow[0] == block:
				thisRow[0] = block
			else:
				thisRow[0] += prevRow[0]
		for j in range(1, n):
			up = prevRow[j]
			left = thisRow[j - 1]
			if thisRow[j] != block:
				if up == block:
					if left == block:
						thisRow[j] = block
					else:
						thisRow[j] += left
				elif left == block:
					thisRow[j] += up
				else:
					thisRow[j] += max(up, left)
		prevRow = thisRow[:]
	final = prevRow[-1]
	if final == block:
		print('NO')
	else:
		print('YES')
		print(final)


def main():
	from sys import stdin, stdout
	rl = stdin.readline
	(n, m) = (int(x) for x in rl().split())
	grid = [[int(x) for x in rl().split()] for _ in range(n)]
	charms = [[int(x) for x in rl().split()] for _ in range(m)]
	n_inf = -9999
	dp = [[n_inf] * n for _ in range(n)]
	for c in charms:
		c[0] -= 1
		c[1] -= 1
		x = max(0, c[0] - c[2])
		while x < n and x <= c[0] + c[2]:
			off = abs(x - c[0])
			y = max(0, c[1] - c[2] + off)
			while y < n and y <= c[1] + c[2] - off:
				dp[x][y] = grid[x][y]
				y += 1
			x += 1
	for x in range(1, n):
		if dp[x - 1][0] == n_inf:
			for x1 in range(x, n):
				dp[x1][0] = n_inf
			break
		dp[x][0] += dp[x - 1][0]
	for y in range(1, n):
		if dp[0][y - 1] == n_inf:
			for y1 in range(y, n):
				dp[0][y1] = n_inf
			break
		dp[0][y] += dp[0][y - 1]
	for x in range(1, n):
		for y in range(1, n):
			m = max(dp[x - 1][y], dp[x][y - 1])
			dp[x][y] = m + dp[x][y] if m != n_inf else n_inf
	if dp[-1][-1] != n_inf:
		stdout.write('YES\n')
		stdout.write(str(dp[-1][-1]))
	else:
		stdout.write('NO')
main()


(n, m) = map(int, input().split())
grid = []
grid_charm = []
cost = []
for i in range(n):
	hehe = [0 for jj in range(n)]
	maggi = [0 for jj in range(n)]
	row = list(map(int, input().split()))
	grid.append(row)
	grid_charm.append(hehe)
	cost.append(maggi)
for i in range(m):
	(x, y, k) = map(int, input().split())
	(x, y) = (x - 1, y - 1)
	for j in range(k + 1):
		for z in range(k + 1):
			if not j + z <= k:
				break
			(alpha, beta, gamma, lol) = (x - j, y - z, x + j, y + z)
			if alpha >= 0:
				if beta >= 0:
					grid_charm[alpha][beta] = 1
				if lol < n:
					grid_charm[alpha][lol] = 1
			if beta >= 0:
				if gamma < n:
					grid_charm[gamma][beta] = 1
			if gamma < n:
				if lol < n:
					grid_charm[gamma][lol] = 1
cost[0][0] = grid[0][0]
for i in range(n):
	for j in range(n):
		lol = -999999999999
		if i > 0:
			if grid_charm[i - 1][j] == 1 and cost[i - 1][j] != -999999999999:
				lol = max(lol, grid[i][j] + cost[i - 1][j])
		if j > 0:
			if grid_charm[i][j - 1] == 1 and cost[i][j - 1] != -999999999999:
				lol = max(lol, grid[i][j] + cost[i][j - 1])
		if grid_charm[i][j] == 0:
			cost[i][j] = -999999999999
		elif not (i == 0 and j == 0):
			cost[i][j] = lol
if cost[n - 1][n - 1] == -999999999999:
	print('NO')
else:
	print('YES')
	print(cost[n - 1][n - 1])


def valid(i, j):
	return 0 <= i < n and 0 <= j < n
(n, m) = map(int, input().split())
a = [list(map(int, input().split())) for _ in range(n)]
g = [[-float('inf')] * n for _ in range(n)]
for _ in range(m):
	(x, y, p) = map(int, input().split())
	x -= 1
	y -= 1
	for i in range(p + 1):
		for j in range(p - i + 1):
			if valid(x + i, y + j):
				g[x + i][y + j] = 0
			if valid(x - i, y + j):
				g[x - i][y + j] = 0
			if valid(x + i, y - j):
				g[x + i][y - j] = 0
			if valid(x - i, y - j):
				g[x - i][y - j] = 0
if g[0][0] != 0:
	print('NO')
	quit()
g[0][0] = a[0][0]
for i in range(n):
	for j in range(n):
		if g[i][j] == 0:
			k = float('-inf')
			if valid(i - 1, j) and g[i - 1][j] > k:
				k = g[i - 1][j]
			if valid(i, j - 1) and g[i][j - 1] > k:
				k = g[i][j - 1]
			g[i][j] = k + a[i][j]
if g[n - 1][n - 1] == float('-inf'):
	print('NO')
else:
	print('YES')
	print(g[-1][-1])


import numpy as np
(n, m) = map(int, input().split())
dp = np.zeros((n, n))
forest = np.zeros((n, n))
for i in range(n):
	forest[i] = list(map(int, input().split()))
for i in range(m):
	(x, y, z) = map(int, input().split())
	x -= 1
	y -= 1
	for i in range(0, z + 1):
		dp[max(x - i, 0)][max(y - (z - i), 0):min(y + (z - i) + 1, n)] = 1
		dp[min(x + i, n - 1)][max(y - (z - i), 0):min(y + (z - i) + 1, n)] = 1
for i in range(n):
	for j in range(n):
		if dp[i][j] != 1:
			forest[i][j] = -np.inf
for i in range(n - 1, -1, -1):
	for j in range(n - 1, -1, -1):
		if j == n - 1:
			if i == n - 1:
				dp[i][j] = forest[i][j]
			else:
				dp[i][j] = forest[i][j] + dp[i + 1][j]
		elif i == n - 1:
			dp[i][j] = forest[i][j] + dp[i][j + 1]
		else:
			dp[i][j] = forest[i][j] + max(dp[i + 1][j], dp[i][j + 1])
if dp[0][0] > -np.inf:
	print('YES')
	print(int(dp[0][0]))
else:
	print('NO')