알고리즘/백준

[백준] 14846 직사각형과 쿼리 - JAVA

체제 2023. 5. 18. 22:44

https://www.acmicpc.net/problem/14846

 

14846번: 직사각형과 쿼리

첫째 줄에 N (1 ≤ N ≤ 300)이 주어진다. 다음 N개의 줄에는 행렬의 정보가 주어지며, 각 줄은 N개의 수로 이루어져 있다. 행은 위에서부터 아래로, 열은 왼쪽부터 오른쪽으로 번호가 매겨져 있으며

www.acmicpc.net

 

 

알고리즘

  • 누적합 알고리즘으로 접근하여 풀기 
  • dp[a][b][c] : (1,1) ~ (a,b) 부분 행렬에 포함되어 있는 정수 c의 갯수 (1 ≤ c ≤ 10) 
  • 특정 위치(a,b)에서 각 정수의 누적 갯수 : dp[a][b][c] = dp[a][b-1][c] + dp[a-1][b][c] - dp[a-1][b-1][c] 
  • (a1,b1)~(a2,b2) 를 기준으로 부분행렬을 만들었을 때 : dp[a2][b2][c] - dp[a2][b1-1][c] - dp[a1-1][b2][c] + dp[a1-1][b1-1][c]

소스 코드

import java.util.*;
import java.io.*;

public class BaekJoon_Solution_14846 {
	public static void main(String[] args) throws Exception{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		int N= Integer.parseInt(br.readLine());
		int[][][] dp = new int[N+1][N+1][11]; //특정 위치에 번호가 몇개 있는지 (번호는 1~10의 자연수) 
		
		StringTokenizer st; 
		int num=0; 
		for(int a=1; a<=N; a++) {
			st= new StringTokenizer(br.readLine(), " "); 
			for(int b=1; b<=N; b++) {
				for(int c=1; c<=10; c++) {
					dp[a][b][c] = dp[a-1][b][c]+dp[a][b-1][c]-dp[a-1][b-1][c]; 
				}
				num = Integer.parseInt(st.nextToken());//해당 위치 의 번호 
				dp[a][b][num]++;  
			}
		}
		
		int Q= Integer.parseInt(br.readLine()); 
		while(Q-- >0) {
			st= new StringTokenizer(br.readLine(), " ");
			int x1= Integer.parseInt(st.nextToken());
			int y1= Integer.parseInt(st.nextToken());
			int x2= Integer.parseInt(st.nextToken());
			int y2= Integer.parseInt(st.nextToken());
		
			int cnt=0; 
			for(int i=1; i<=10; i++) {
				if((dp[x2][y2][i]-dp[x2][y1-1][i]-dp[x1-1][y2][i]+dp[x1-1][y1-1][i]) >0 ) cnt++;
			}
			System.out.println(cnt);
		}
	}//end of main 
}//end of class