Koder / 박성훈
article thumbnail

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

 

2473번: 세 용액

첫째 줄에는 전체 용액의 수 N이 입력된다. N은 3 이상 5,000 이하의 정수이다. 둘째 줄에는 용액의 특성값을 나타내는 N개의 정수가 빈칸을 사이에 두고 주어진다. 이 수들은 모두 -1,000,000,000 이상

www.acmicpc.net

이분탐색 문제이다.

세 수를 선정할 때에, O(N^3) 브루트포싱으로 접근하면 시간초과를 받게 되므로

세 숫자 중 하나는 이분탐색을 통해서 골라내야 한다.

 

O(N^2) 로 두개의 쌍을 더해서 그 합 SUM 을 만들어 주고,

SUM의 음수와 가장 가까운 수를 이분탐색으로 구해준 다음

셋의 합이 0에 가까워지도록 갱신해나가면 된다.

 

이때, lower_bound로 구한 인덱스가 k라고 치면

k-1, k 두개의 인덱스가 가장 가까운 수가 될 수 있는 후보군에 해당하는데,

k는 N이 될 수 없고, k-1은 -1이 될 수 없음에 유의해야 한다.

배열 인덱스를 벗어나지 않도록 잘 관리해주자.

 

이때 두개의 수를 더해서 vector에 넣어 저장하면, 메모리 초과를 받게 될 수 있다.

하나의 반복문 내에서 전부 처리해야 할듯.

 

수 범위가 크니 long long 형을 사용하도록 하자.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

vector<ll> arr;

int main(){
	int N,tmp;
	cin >> N;
	for(int i=0; i<N; i++){
		cin >> tmp;
		arr.push_back(tmp);
	}
	
	sort(arr.begin(), arr.end());
	
	ll ans = 1e18;
	ll ret[3] = {0};
	
	for(int i=0; i<N; i++){
		for(int j=i+1; j<N; j++){
			auto k = lower_bound(arr.begin(), arr.end(), (arr[i]+arr[j])*-1) - arr.begin();
					
			if(k>0){
				if(i!=k-1 && j!=k-1 && ans>abs(arr[k-1]+arr[i]+arr[j])){
					ans = abs(arr[k-1]+arr[i]+arr[j]);
					ret[0] = i;
					ret[1] = j;
					ret[2] = k-1;
				}
			}
			if(k<N){
				if(i!=k && j!=k && ans>abs(arr[k]+arr[i]+arr[j])){
					ans = abs(arr[k]+arr[i]+arr[j]);
					ret[0] = i;
					ret[1] = j;
					ret[2] = k;
				}
			}
		}
	}

	sort(ret, ret+3);
	for(int i=0; i<3; i++) cout << arr[ret[i]] << " ";
	return 0;
}

반응형