#11659 구간 합 구하기4
#11660 구간 합 구하기5
구간 합 구하기 문제의 핵심은 누적합을 Memoization 기법을 사용하여 해결하는 것이다
N과 M이 최대 100,000
이기 때문에 그냥 for문을 돌려서 찾을 경우 최악의 경우 100,000X100,000
번 연산을 수행해야 하기 때문에 시간 초과가 발생
accu[i]
는 accu[i-1] (이전까지의 합)
에 현재 숫자를 더해준 값을 저장한다to
에서부터 from
까지의 구간합을 구할 때, to
까지의 구간 합 즉, accu[to]
에서 from
이전까지의 구간합 accu[from-1]
을 빼준다import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class BOJ11659 {
static int N, M;
static int[] accu;
public static void main(String[] args) throws IOException{
BufferedReader br=new BufferedReader (new InputStreamReader (System.in));
StringTokenizer st=new StringTokenizer(br.readLine());
N=Integer.parseInt(st.nextToken());
M=Integer.parseInt(st.nextToken());
accu=new int[N+1];
st=new StringTokenizer(br.readLine());
for (int i=1; i<=N; i++) {
accu[i]=Integer.parseInt(st.nextToken())+accu[i-1];
}
//M개의 구간 합
StringBuilder sb=new StringBuilder();
for (int i=0; i<M; i++) {
st=new StringTokenizer (br.readLine());
int from=Integer.parseInt(st.nextToken());
int to=Integer.parseInt(st.nextToken());
sb.append(accu[to]-accu[from-1]).append("\n");
}
System.out.println(sb.toString());
}
}
위의 그림과 같이 처음 시작점을 (x1, y1)이라 하고 도착 지점을 (x2, y2)라 했을 때, 빨간 구역은 (x1, y2) + (x1+1, y2) + .... + (x2, y2)
이고 초록색 구역은 (x1, y1-1) + (x1+1, y1-1) + ..... + (x2, y1-1)
으로 계산한다
식으로 나타내면 아래와 같다
for (int x=x1; x<=x2; x++)
sum+=accu[x][y2]-accu[x][y1-1];
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
static int N,M;
static int[][] accu; // <= 이전 수부터 합을 미리 계산, 행별로 각각 누적 계산
public static void main(String[] args) throws IOException{
BufferedReader br=new BufferedReader (new InputStreamReader (System.in));
StringTokenizer st=new StringTokenizer(br.readLine());
N=Integer.parseInt(st.nextToken());
M=Integer.parseInt(st.nextToken());
accu=new int[N+1][N+1];
for (int i=1; i<=N; i++) {
st=new StringTokenizer (br.readLine());
//행별 누적 계산
for (int j=1; j<=N; j++) {
accu[i][j]=accu[i][j-1]+Integer.parseInt(st.nextToken());
}
}
StringBuilder sb=new StringBuilder ();
for (int i=0; i<M; i++) {
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 sum=0;
for (int x=x1; x<=x2; x++) {
sum+=accu[x][y2]-accu[x][y1-1];
}
sb.append(sum).append("\n");
}
System.out.println(sb.toString());
}
}
(x1, y1)
, 도착 좌표를 (x2, y2)
라고 할 때, 주황색 영역=accu[x2][y2]
, (3)번의 초록색 영역=accu[x1-1][y2]
, (4)번의 초록색 영역=accu[x2][y1-1]
, 중복되는 영역=accu[x-1][y1-1]
이고 이를 식으로 나타내면 아래와 같다accu[x2][y2]-accu[x1-1][y2]-accu[x2][y1-1]+accu[x1-1][y1-1]
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
static int N,M;
static int[][] accu; // <= 이전 수부터 합을 미리 계산, 행별로 각각 누적 계산
public static void main(String[] args) throws IOException{
BufferedReader br=new BufferedReader (new InputStreamReader (System.in));
StringTokenizer st=new StringTokenizer(br.readLine());
N=Integer.parseInt(st.nextToken());
M=Integer.parseInt(st.nextToken());
accu=new int[N+1][N+1];
for (int i=1; i<=N; i++) {
st=new StringTokenizer (br.readLine());
//행과 열을 모두 합한 누적 계산, 현재 좌표 기준으로 원점 (시작점)과ㅏ의 사각형내의 모든 합
for (int j=1; j<=N; j++) {
accu[i][j]=accu[i-1][j]+accu[i][j-1]-accu[i-1][j-1]+Integer.parseInt(st.nextToken());
}
}
StringBuilder sb=new StringBuilder ();
for (int i=0; i<M; i++) {
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 sum=0;
sb.append(accu[x2][y2]-accu[x1-1][y2]-accu[x2][y1-1]+accu[x1-1][y1-1]).append("\n");
}
System.out.println(sb.toString());
}
}