그리디 알고리즘, 누적합을 사용
N이 100,000 까지이므로 O(N^2) 으로는 풀 수 없을 것으로 생각. O(N^2) 이라면 이중 for문으로 모든 경우의 수를 체크하는 간단한 방법으로 해결할 수 있었을 것이다.
10분쯤 경과했을 때 누적합으로 풀 수 있을 것으로 생각했고,
어떤 조건으로 벌집과 벌의 위치를 조절해야하는지를 가장 많이 고민했다.
고민한 결과는 우선 이 문제를 3가지 경우의 수로 나누어 보는 것이다.
벌 - 벌 - 벌집
벌 - 벌집 - 벌
벌집 - 벌 - 벌
의 3가지 경우의 수가 나올 수 있고,
각각에 대해서 따로 누적합을 계산해줌으로써
가장 큰 값을 출력하면 된다는 결론을 내렸다.
가운데에 벌집이 있는 경우는 비교적 쉬웠으나,
벌 - 벌 - 벌집
과 벌집 - 벌 - 벌
은 어떻게 벌의 위치를 조절해줘야 되는지를 계속 고민함. 처음에는 무조건 벌을 가장 왼쪽에 2마리 배치시키는 쪽으로 생각했는데 문제의 예시만 봐도 그것이 답이 아님을 알 수 있었다. 여기서 누적합을 응용해서
우선 벌 1마리는 가장 끝에 배치 시키고
, 그 후에 O(N) 으로 계속 누적합을 비교해가면서 어떤 경우가 가장 많은지 계산하는 방법으로 문제를 해결했다.
3가지 모두 각각의 경우에 대해서는 누적합을 구하는 데에도 O(N) 이고, 누적합을 구한 후에도 각각의 경우에 대해서 벌의 위치를 조절하는데에도 O(N) 이므로 총 시간복잡도는 O(N) 이 걸림.
import java.util.*;
import java.io.*;
public class Main{
static int arr[];
public static void main(String[] args) throws IOException{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb=new StringBuilder();
StringTokenizer st;
int n=Integer.parseInt(br.readLine());
st=new StringTokenizer(br.readLine());
arr=new int[n+1];
for(int i=1;i<arr.length;i++) {
arr[i]=Integer.parseInt(st.nextToken());
}
int left = leftHoney();
int right = rightHoney();
int mid = midHoney();
int max=Math.max(left,Math.max(right,mid));
System.out.println(max);
}
public static int leftHoney() { //벌통이 오른쪽에 위치
int sum[]=new int[arr.length];
for(int i=2;i<arr.length;i++)
sum[i]=sum[i-1]+arr[i-1];
int endSum=sum[arr.length-1];
int max=0;
for(int i=1;i<arr.length-1;i++) {
max=Math.max(max,endSum-arr[i]+sum[i]);
}
return max;
}
public static int rightHoney() { //벌통이 왼쪽에 위치
int sum[]=new int[arr.length];
for(int i=arr.length-2;i>=1;i--)
sum[i]=sum[i+1]+arr[i+1];
int endSum=sum[1];
int max=0;
for(int i=2;i<arr.length;i++)
max=Math.max(max,endSum-arr[i]+sum[i]);
return max;
}
public static int midHoney() { //벌통이 가운데에 위치
int leftSum[]=new int[arr.length];
int rightSum[]=new int[arr.length];
for(int i=2;i<leftSum.length;i++)
leftSum[i]=leftSum[i-1]+arr[i];
for(int i=rightSum.length-2;i>=1;i--)
rightSum[i]=rightSum[i+1]+arr[i];
int max=0;
for(int i=1;i<arr.length;i++)
max=Math.max(max,leftSum[i]+rightSum[i]);
return max;
}
}
이런 서브태스크 있는 문제는 틀리면 틀렸지 괜히 애매하게 50점, 70점 맞을 때가 더 거슬릴 때가 있다. 다행히 한 번에 100점을 받았다.
한 2주 동안 다른일 한다고 포스팅도 못하고 알고리즘 문제도 제대로 안 풀었는데 이제 다시 오늘부터 알고리즘 문제를 1일 최소 1커밋 이상씩은 할 예정이다.
하루에 백준 1문제 이상 푸는 것을 목표로 하고있다.
https://solved.ac/profile/anwlro0212