공부공간

BOJ - 12846 ) 무서운 아르바이트 본문

알고리즘/SegmentTree

BOJ - 12846 ) 무서운 아르바이트

개발자가될수있을까? 2021. 7. 28. 22:16

 


 

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

 

12846번: 무서운 아르바이트

성화는 악독하기로 유명한 편의점 사장이다. 그의 편의점에는 특이한 임금 체계를 가지고 있다. 각 날마다 일의 차이때문에 일마다 급여가 정해져 있다. 돈은 당일에 주지 않고 퇴직을 할 때 한

www.acmicpc.net


연속한 수열에서 가장 최솟값을 기준으로 얻을 수 있는 총합의 가장 큰 값을 고르는 문제이다.

 

문제상황을 잘 읽어보면,

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

 

6549번: 히스토그램에서 가장 큰 직사각형

입력은 테스트 케이스 여러 개로 이루어져 있다. 각 테스트 케이스는 한 줄로 이루어져 있고, 직사각형의 수 n이 가장 처음으로 주어진다. (1 ≤ n ≤ 100,000) 그 다음 n개의 정수 h1, ..., hn (0 ≤ hi ≤

www.acmicpc.net

 

이 문제와 완전한 동치임을 알 수 있다. 즉 가장 큰 직사각형의 넓이를 구하기위해,

밑변을 세그먼트트리의인덱스로 설정하고 해당 수열에서 가장 낮은 ( 높이를 결정하는 ) 값의 인덱스를

세그먼트 트리에 넣어두었다.

 

또한 재귀함수를 통하여, 밑변의 길이가 1인 직사각형까지 모두 탐색한다.

즉, 연속된 날짜에 아르바이트를 하더라도, 가장 낮은임금을 기준으로 급여를 받기 때문에,

가장 낮은 임금의 인덱스를 저장하며 직사각형처럼 풀어준다.

 

재귀의 다음 STEP으로는 현재 인덱스의 좌우를 변수로 주어탐색한다.


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class 무서운아르바이트 {
	
	public static int n;
	public static int arr[];
	public static int seg[];
	public static long answer = -1;
	public static int out = 987654321;
	public static void main(String[] args) throws IOException {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		n = Integer.parseInt(st.nextToken());
		st = new StringTokenizer(br.readLine());
		arr = new int[n]; seg=new int[4*n];
		for(int i=0;i<n;++i) {arr[i]=Integer.parseInt(st.nextToken());}
		seginit(1,0,n-1);
		dfs(0,n-1);
		System.out.println(answer);
	}
	
	private static void dfs(int s, int e) {
		if(e<s)return;
		if(s==e) {
			long res = arr[e];
			answer = answer > res ? answer : res;
			return ;
		}
		int index = findmin(1,0,n-1,s,e);
		long res = (long)(e-(s-1)) * (long)arr[index];
		answer = answer > res ? answer : res;
		dfs(s,index-1);
		dfs(index+1,e);
	}

	private static int seginit(int now, int s, int e) {
		// 구간의 가장작은 높이의 인덱스를 저장
		if(s==e) {return seg[now] = s;}
		else {
			int l = seginit(now*2,s,(s+e)>>1);
			int r = seginit(now*2+1,((s+e)>>1)+1,e);
			return (seg[now] = (arr[l]>arr[r]?r:l));		
		}
	}
	
	private static int findmin(int node, int l, int r , int s  , int e) {
		if(r < s || e < l) return out;
		else if( s <= l && r<= e) return seg[node];
		int rr = findmin(2*node, l, (r+l)>>1, s, e);
		int ll = findmin(2*node+1, ((r+l)>>1)+1, r, s, e);
		if(rr==out && ll!= out) return ll;
		if(rr!=out && ll== out) return rr;
		// 둘다 out인경우가? 존재할수 없다
		return arr[rr] > arr[ll] ? ll : rr ;
	}
}

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

BOJ - 1306 ) 달려라 홍준  (0) 2021.07.27
BOJ - 6549 ) 히스토그램에서 가장 큰 직사각형  (0) 2020.10.28
BOJ -2268 ) 수들의 합  (0) 2020.05.17
BOJ - 10868 ) 최솟값  (0) 2020.05.16
BOJ - 2357 ) 최솟값과 최댓값  (0) 2020.05.16
Comments