※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 16789번 문제인 イルミネーション (Illumination)이다.
문제는 아래 링크를 확인하자.

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

 

16789번: イルミネーション (Illumination)

この入力例では,木 1, 4 にイルミネーションを飾り付けると,美しさの合計が 9 となり最大となる.L_1 = 2, R_1 = 4 なので,木 2, 3, 4 のうち 2 つ以上にイルミネーションを飾り付けることはで

www.acmicpc.net

dp[i]를 "첫 나무부터 i번째 나무까지를 장식해 얻을 수 있는 최대 아름다움"이라 정의하자.

 

이 때, 첫 나무부터 i번째 나무까지 꾸미는 방법은 1) i번째 나무에 illumination을 붙이는 경우와 2) i번째 나무에 illumination을 붙이지 않는 경우 두 종류로 나눌 수 있다.

 

1) i번째 나무에 illumination을 붙인다면, M개의 구간 중 해당 나무를 포함하는 구간에 포함된 나무들에는 illumination을 붙일 수 없게 된다. 그러한 구간은 어떤 j에 대하여 [j,i]의 형태로 나타날 수밖에 없다. 따라서 첫 나무부터 i번째 나무까지 꾸미면서 i번째 나무에 illumination을 붙이는 경우의 아름다움의 최댓값은 dp[i-j-1] + (i번째 나무에 illumination을 붙일 때의 아름다움)이 된다.

2) i번째 나무에 illumination을 붙이지 않는 경우 dp[i]는 dp[i-1]과 같게 된다.

 

위 둘을 이용해 dp 점화식을 세워 문제를 해결하자.

 

1)의 계산에 필요한 j의 위치는 M개의 구간 [l,r]을 l을 기준으로 오름차순으로 정렬해 sweeping하는 것으로 O(N + MlgM)의 시간복잡도로 전처리할 수 있다.

 

아래는 제출한 소스코드이다.

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;

int N, M;
int arr[200001];
int leftmost[200001];
ll dp[200001];
vector<pair<int, int>> seg;

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> N >> M;
	for (int i = 1; i <= N; i++) cin >> arr[i];
	
	while (M--) {
		int x, y; cin >> x >> y;
		seg.emplace_back(make_pair(x, y));
	}
	sort(seg.begin(), seg.end());
	int idx = 1;
	for (auto& p : seg) {
		while (idx < p.first) {
			leftmost[idx] = idx;
			idx++;
		}
		while (idx <= p.second) {
			leftmost[idx] = p.first;
			idx++;
		}
	}
	while (idx <= N) {
		leftmost[idx] = idx;
		idx++;
	}

	for (int i = 1; i <= N; i++) {
		dp[i] = max(dp[i - 1], dp[leftmost[i] - 1] + arr[i]);
	}

	cout << dp[N];
}
728x90

+ Recent posts