n*n 배열에서 왼쪽 위가 (x1,y1), 오른쪽 아래가 (x2,y2)인 직사각형에 포함되는 서로 다른 정수의 개수를 찾는 쿼리가 많이 주어질 때 이 쿼리에 답한다
-------------------------------------------------------------------------------------------------------
n이 300인데 여기서 핵심은 행렬이 포함하고 있는 정수가 10까지라는 것이다
dp[y][x][i]를 왼쪽 위가 (0,0)이고 오른쪽 아래가 (x,y)인 직사각형에 포함된 정수 i의 개수로 정의한다
x,y가 300까지이고 i가 10까지니까 900000 정도로 메모리 적당
나머지는 여기서 배운 테크닉대로 하면 된다
https://deepdata.tistory.com/1031
2차원 배열에서의 누적합 배열을 구하는 방법 배우기
1. 문제 11660번: 구간 합 구하기 5 (acmicpc.net) 11660번: 구간 합 구하기 5 첫째 줄에 표의 크기 N과 합을 구해야 하는 횟수 M이 주어진다. (1 ≤ N ≤ 1024, 1 ≤ M ≤ 100,000) 둘째 줄부터 N개의 줄에는 표에
deepdata.tistory.com
y = 0일때 x축으로 dp[0][x][i]를 채운다
dp[0][x][maps[0][x]] += 1을 하고, 모든 i = 1,2,3,..,10에 대하여 dp[0][x][i] += dp[0][x-1][i]
x = 0일때 y축으로 dp[y][0][i]를 채운다
dp[y][0][maps[y][0]] += 1을 하고, 모든 i = 1,2,3...,10에 대하여 dp[y][0][i] += dp[y-1][0][i]
이후 x,y = 1,2,..,n-1에 대하여
dp[y][x][maps[y][x]] += 1을 하고 모든 i = 1,2,3...,10에 대하여
dp[y][x][i] = dp[y-1][x][i] + dp[y][x-1][i] - dp[y-1][x-1][i]
from sys import stdin
n = int(stdin.readline())
maps = [list(map(int,stdin.readline().split())) for _ in range(n)]
dp = [[[0]*11 for _ in range(n)] for _ in range(n)]
dp[0][0][maps[0][0]] = 1
for x in range(1,n):
dp[0][x][maps[0][x]] += 1
for i in range(1,11):
dp[0][x][i] += dp[0][x-1][i]
for y in range(1,n):
dp[y][0][maps[y][0]] += 1
for i in range(1,11):
dp[y][0][i] += dp[y-1][0][i]
for y in range(1,n):
for x in range(1,n):
dp[y][x][maps[y][x]] += 1
for i in range(1,11):
dp[y][x][i] += (dp[y-1][x][i] + dp[y][x-1][i] - dp[y-1][x-1][i])
이후에 쿼리 (x1,y1), (x2,y2)가 주어지면... 서로 다른 정수의 개수를 찾는 방법은?
모든 i = 1,2,..,10에 대하여 사각형 내부에 i의 개수를 찾는다
dp[y2][x2][i] - dp[y1-1][x2][i] - dp[y2][x1-1][i] + dp[y1-1][x1-1][i]
이 값이 1 이상이면, 해당 사각형 내부에는 정수 i가 1개 이상 있다는 뜻이므로, 1을 더해준다
0이면 정수 i가 존재하지 않으니 0을 더해주는
q = int(stdin.readline())
for _ in range(q):
y1,x1,y2,x2 = map(int,stdin.readline().split())
x1 -= 1
y1 -= 1
x2 -= 1
y2 -= 1
count = 0
for i in range(1,11):
A = dp[y2][x2][i]
if y1 == 0:
B = 0
else:
B = dp[y1-1][x2][i]
if x1 == 0:
C = 0
else:
C = dp[y2][x1-1][i]
if x1 == 0 or y1 == 0:
D = 0
else:
D = dp[y1-1][x1-1][i]
count += min((A - B - C + D),1)
print(count)
'알고리즘 > 누적 합 알고리즘' 카테고리의 다른 글
임의의 직사각형에 포함된 정수 중 최대 최소의 차이를 빠르게 찾는 2차원 배열 누적합 (0) | 2025.02.10 |
---|---|
높이가 작은 인접한 성냥으로 불을 옮길 때 가장 많은 성냥에 불을 태우는 방법 (0) | 2024.08.21 |
누적 합으로 i < j < k < l을 돌아버리는 미친 다이나믹 프로그래밍 테크닉 (0) | 2024.07.16 |
코딩테스트 복기 - 구간합이 전부 똑같도록 3구간으로 나누는 방법(잘 모를때는 조건식을 써봐라) (0) | 2024.04.27 |
prefix sum만이 누적합이 아니다1 - value 누적합 (0) | 2024.04.10 |