본문 바로가기
Algorithm/동적계획법(DP)

13398 연속합 2

by neohtux 2020. 3. 26.
728x90

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

 

13398번: 연속합 2

첫째 줄에 정수 n(1≤n≤100,000)이 주어지고 둘째 줄에는 n개의 정수로 이루어진 수열이 주어진다. 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다.

www.acmicpc.net

연속합 2 성공

시간 제한메모리 제한제출정답맞은 사람정답 비율

2 초 512 MB 4952 1567 1124 30.527%

문제

n개의 정수로 이루어진 임의의 수열이 주어진다. 우리는 이 중 연속된 몇 개의 수를 선택해서 구할 수 있는 합 중 가장 큰 합을 구하려고 한다. 단, 수는 한 개 이상 선택해야 한다. 또, 수열에서 수를 하나 제거할 수 있다. (제거하지 않아도 된다)

예를 들어서 10, -4, 3, 1, 5, 6, -35, 12, 21, -1 이라는 수열이 주어졌다고 하자. 여기서 수를 제거하지 않았을 때의 정답은 12+21인 33이 정답이 된다.

만약, -35를 제거한다면, 수열은 10, -4, 3, 1, 5, 6, 12, 21, -1이 되고, 여기서 정답은 10-4+3+1+5+6+12+21인 54가 된다.

입력

첫째 줄에 정수 n(1≤n≤100,000)이 주어지고 둘째 줄에는 n개의 정수로 이루어진 수열이 주어진다. 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다.

출력

첫째 줄에 답을 출력한다.

 

 

<풀이>

1. 가장 긴 바이토닉 부분 수열을 응용해서 풀 수 있다.

 

2. a1, a2, a3, a4, ..... , a(N-1), a(N) 이라는 임의의 수열이 있을때

임의의 원소가 a[k] 번째 라고 한다면, 문제의 조건에서 어떤 원소를 제거해도 되고 안해도 된다라는 조건이 있기때문에,  a[1] + .... +a[k-1]  + a[k+1] +a[k+2] .... 를 하면 된다.

 

3. 물론 입력될 원소의 개수가 적다면 하나를 제거하고( 0으로 만들고) 다음 원소부터

계속 비교해보고 N번을 N번 비교하므로 O(N^2)으로 할 수 있다. 하지만 입력 데이터 개수가

10만이라면 10만^2이 되버리기때문 연산횟수가 평균 1초 1억이라고했을때 그 수를 훨씬 뛰어 넘기 때문, 시간초과가 발생한다.

 

4. 

 D [0][i] : 특정 원소를 제거 하지 않은 연속합,

 D [1][i] : 특정 원소를 제거한 연속합 이라고 한다면

 

D[0][i] 와 D[1][i]의 제거될 원소 i를 제외하고 둘이 더한 연속의 합의 합을 구할 수 있다.

 

ex ) D[0][i-1]  ,   i(제거될 원소) ,  D[1][i+1]

 

5. 제거 하지 않고도 가장 큰 값이 나올 수 있기때문

 먼저 제거하지 않은 상태에서 최대값을 구해보고, 그 값과 대소 비교를 통해

 구할 수 있다.

 

6. 두 조건의 연속합을 합치기 위해서 D[1][i]를 역으로 구해야 한다.

왜냐하면,

D[0][1] D[0][2]   .. ... D[0][i] D[0][i+1]..

D[1][1] D[1][2]   .. ... D[1][i] D[1][i+1]..

이 두개를 합치려면  i번째 이전의 값들에는 이미 제거 하지 않은 연속합의 부분이 겹치기

떄문이다. 

 

7. 이 겹치는 부분에서 발생할 수 있는 오류를 피하기위해

---------->(연속합 최대)   (제거 원소 i번째 )    (연속합 최대) <--------------

                D[0][i-1]                                    D[1][i+1]

이처럼 두개를 더하면서 각각이 i를 N번씩 다 순회하며 최대값의 합을 찾으면 된다.

 

#include<iostream>
#include<algorithm>
using namespace std;

int arr[100001];
int d[2][100001];
int main(void)
{
	int N;
	cin >> N;
	for (int i = 1; i <= N; ++i)
	{
		cin >> arr[i];
	}

	//d[0][n] = 제거 하지 않은, d[1][n] = 제거 한 경우
	for (int i = 1; i <= N; ++i)
	{
		d[0][i] = arr[i];
		if (i == 1) continue;
		d[0][i] = max(d[0][i - 1] + arr[i], arr[i]);

	}
	for (int i = N; i >= 1; --i)
	{
		d[1][i] = arr[i];
		if (i == N) continue;
		d[1][i] = max(d[1][i + 1] + arr[i], arr[i]);
	}
	int ans = -1001;

	for (int i = 1; i <= N; ++i)
	{
		if (ans < d[0][i]) ans = d[0][i];
	}

	for (int i = 2; i <= N; ++i)
	{
		if (ans < d[0][i - 1] + d[1][i + 1])
			ans = d[0][i - 1] + d[1][i + 1];
	}

	cout << ans << '\n';
	return 0;
}

 

   

300x250

'Algorithm > 동적계획법(DP)' 카테고리의 다른 글

17404 RGB거리 2  (0) 2020.03.26
11054 가장 긴 바이토닉 부분 수열  (2) 2020.03.26
11722 가장 긴 감소하는 부분 수열  (0) 2020.03.26
11055 가장 큰 증가 부분 수열  (0) 2020.03.26
1932 정수 삼각형  (0) 2020.03.24

댓글