# 연속합 import sys input = sys.stdin.readline def solution(): n = int(input().rstrip()) lst = [0]+list(map(int, input().rstrip().split())) prefix_sum = [0] * (n+1) min_lst = [0]*(n+1) prefix_sum[0] = 0 min_lst[0] = 0 now_min = 0 for i in range(1, n+1): prefix_sum[i] = prefix_sum[i-1] + lst[i] min_lst[i] = now_min now_min = min(now_min, prefix_sum[i]) result = float('-inf') for i in range(1, n+1): result = max(result, prefix_sum[i]-min_lst[i]) print(result) return solution() """ 걸린 시간: 30분 시간 복잡도: 모든 계산과 반복은 O(n)에 끝난다. 해설: 연속된 부분합을 편하게 다루기 위해 prefix_sum을 생각하였다. 그 후 prefix_sum들을 살펴보니, 모든 prefix_sum에 대해서 그 앞에 있는 것들 중 제일 작은 prefix_sum 빼면 최대가 나올 것 같았다. 그럼 그 구간의 제일 작은 것들을 매번 찾을 수는 없으니, prefix_sum을 계산하면서 제일 작은 것을 기록해야겠다고 생각했다. 그렇게 되면 계속 O(n)으로 다 처리할 수 있다. 제일 작은 것을 기록하려다보니 계산된 prefix_sum 중에 작은 것을 기록하려고 했는데, 사실 계산된 prefix_sum이 음수가 아닌 이상, 제일 작은 것은 0이 맞다. 따라서 계산된 prefix_sum 이전에 0을 넣고, 쭉 계산을 진행했다. 마지막 반복문으로 result를 모든 prefix_sum에 대해 그 구간의 최소값을 빼보며 result의 최대값을 구했다. 이 논리를 좀 더 직관적으로 말하는 풀이법이 있는 kadane라는 것이다. dp[i]를 볼때 i번째 숫자로 새로 시작할지, 기존 최적 수열에 i를 붙일지 선택하는 것이다. lst[i] > dp[i] + lst[i]라는 뜻은 지금까지 최선을 다해온 팀이 있는데, 내가 들어가는 것보다 나 혼자 시작하는게 더 나은 경우이다. lst[i] < dp[i] + lst[i]라는 뜻은 내가 너무 멍청해서 팀원들이 플러스 역할을 해준다는 경우이다. 이 나혼자 새로 시작한다는 시점이 바로 내 풀이의 now_min이 바뀌는 시점이다. 너무 벌레를 만나서 그 벌레를 끊고 이후부터 새로 시작했다는 뜻이다. 여기서도 result를 계속 max값 업데이트를 해줘야하는데 관계를 끊고 새로 시작했다고 해도, 어떤 팀들은 이미 최고의 플레이를 했을 수도 있기 때문이다. """