본문 바로가기

알고리즘/백준

백준 2104 부분배열 고르기

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

 

2104번: 부분배열 고르기

문제 크기가 N(1≤N≤100,000)인 1차원 배열 A[1], …, A[N]이 있다. 어떤 i, j(1≤i≤j≤N)에 대한 점수는, (A[i]+…+A[j])×Min{A[i], …, A[j]}가 된다. 즉, i부터 j까지의 합에다가 i부터 j까지의 최솟값을 곱한 ��

www.acmicpc.net

세그먼트 트리를 활용한 문제다.

 

그냥 재귀를 활용할 수도 있지만 

 

만약 가장 작은 수가 배열의 양 끝일 경우 O(N^2)가 되기 때문에 시간초과에 걸린다.

 

그리고 자료형도 신경써야한다.

 

pair<long long int, long long int>를 활용한 세그먼트 트리로 해결했다

 

 

/* 부분 배열 고르기 */

#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>

#define pp pair<long long int,long long int>
#define ll long long int 

using namespace std;

void input();
void solve();
pp seg_init(int, int, int);
pp seg_find(int, int, int, int, int);

ll n_of_arr, arr[100000], ans;
vector<pp> tree;

int main(void) {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);

	input();
	solve();

	return 0;
}

void input() {
	cin >> n_of_arr;
	for (int i = 0; i < n_of_arr; i++) {
		cin >> arr[i];
	}

	ll height = ceil(log2(n_of_arr) + 1);
	tree.resize(1 << (height + 1));
}

void divide(int l, int r) {
	if (l > r) return;
	pp curr = seg_find(0, n_of_arr-1, l, r, 1);
	//cout << l << " " << r << " " << curr.first << " " << curr.second << endl;
	
	ans = max(ans, arr[curr.first] * curr.second);

	divide(l, curr.first - 1);
	divide(curr.first + 1, r);

}

void solve() {
	seg_init(0, n_of_arr-1, 1);
	divide(0, n_of_arr-1);

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

pp seg_init(int start, int end, int node) {
	// first minvalue second summation
	if (start == end) {
		tree[node].first = start;
		tree[node].second = arr[start];
		return tree[node];
	}
	ll mid = (start + end) / 2;

	pp temp1 = seg_init(start, mid, node * 2);
	pp temp2 = seg_init(mid + 1, end, node * 2 + 1);
	
	tree[node].first = (arr[temp1.first] > arr[temp2.first] ? temp2.first : temp1.first);
	tree[node].second = (temp1.second + temp2.second);

	return tree[node];
}

pp seg_find(int start, int end, int left , int right, int node) {
	if (end < left || right < start) return { -1, 0 };
	if (left <= start  &&end <= right) return tree[node];
	else {
		int mid = (start + end) / 2, idx;
		pp t1 = seg_find(start, mid, left, right, node * 2);
		pp t2 = seg_find(mid + 1, end, left, right, node * 2 + 1);

		if (t1.first == -1) {
			return t2;
		}
		else if (t2.first == -1) {
			return t1;
		}
		else {
			idx = (arr[t1.first] > arr[t2.first] ? t2.first : t1.first);
			return { idx, t1.second + t2.second };
		}
	}
}

'알고리즘 > 백준' 카테고리의 다른 글

백준 2493 탑 C++  (0) 2020.08.17
백준 10868 최솟값  (0) 2020.08.16
백준 2014 소수의 곱  (0) 2020.08.14
백준 10159 저울  (0) 2020.08.14
백준 1976 여행가자  (0) 2020.08.14