• [백준OJ] 14575번 뒤풀이

    2021. 9. 15.

    by. Hyeon-Uk

    반응형

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

     

    14575번: 뒤풀이

    첫째 줄에 대회 참가자의 수 N과 술의 총량 T가 주어진다. (1 ≤ N ≤ 1000, 1 ≤ T ≤ 109) 둘째 줄부터 N개의 줄에 걸쳐, 각 사람에 대한 Li와 Ri값이 주어진다. (1 ≤ Li ≤ Ri ≤ 106)

    www.acmicpc.net


     

    풀이

    먼저, 각 사람들이 최대주량으로 마셨을때 T보다 작거나, 각 사람들이 최소 주량으로 마셨을때 T보다 크다면, 어떠한 경우에도 정확히 T를 맞출 수 없으니 -1을 출력해준다.

     

    위를 통과한다면 이분탐색을 이용하여 문제를 해결한다.

    이분탐색을 이용하여 S를 설정해준 뒤, S를 가지고 해당 인원들을 정확히 T만큼 먹일 수 있는지 확인을 한다.

     

    자신의 주량범위 안에서, S를 초과하지 않고 정확히 T만큼 먹일 수 있는지 확인을 할 수 있는 방법은, 먼저 모든 인원을 최소량 만큼 먹인다고 가정을 한다. 이떄 자신의 최소 주량을 먹였다면, 각 사람마다 더 마실 수 있는 양이 있을것이다.

     

    예를들어 A의 주량이 최소=10, 최대=20이고, S=15라고 했을때, 이사람이 10만큼 마셨다고 가정을 하면, 5만큼을 더 마실수 있다.

    B의 주량이 최소=5, 최대 8이고, S는 똑같이 15라고 했을때, 이사람이 5만큼 마셨다고 가정을 하면, 3만큼을 더 마실 수 있다.

     

    이렇게 각 사람마다 최소의 술을 먹었을때, 더 먹을 수 있는 술의 양을 모두 더해준다. 이 더 먹을 수 있는 양을 More라고 할때,  More의 양이 현재까지 마시고 남은 술의 양보다 크거나 같다면, 위의 조건을 만족하는 S라고 할 수 있다.

    왜냐하면 남은 술을 더 마실 수 있는 사람들에게 나누어 주면, T의 술을 정확히 마시게 할 수 있기 때문이다.

     

     

    시간복잡도

    이분탐색이므로, O(Nlog(Max(R)) 이 된다.

     

    코드

    #include<iostream>
    #include<algorithm>
    #include<vector>
    #define MAX	1e9
    using namespace std;
    
    typedef long long ll;
    typedef pair<int, int> pii;
    
    int n, t;
    vector<pii> v;
    
    bool can(int s) {
    	ll more = 0;
    	ll min_sum = 0;
    	for (int i = 0; i < n; i++) {
    		if (v[i].first > s) {
    			return false;
    		}
    		more += (min(s, v[i].second)-v[i].first);
    		min_sum += v[i].first;
    	}
    	if (more >= t - min_sum) return true;
    	return false;
    }
    
    int main() {
    	ios_base::sync_with_stdio(0);
    	cin.tie(0);
    	cin >> n >> t;
    	ll min_sum = 0;
    	ll max_sum = 0;
    	int left = 0;
    	int right = 0;
    	for (int i = 0; i < n; i++) {
    		int l, r;
    		cin >> l >> r;
    		min_sum += l;
    		max_sum += r;
    		right = max(right, r);
    		v.push_back({ l,r });
    	}
    	if (t < min_sum||max_sum<t) {
    		cout << -1;
    		return 0;
    	}
    	int answer = MAX;
    	while (left <= right) {
    		int s = (left + right) / 2;
    		if (can(s)) {
    			answer = min(answer,s);
    			right = s - 1;
    		}
    		else {
    			left = s+1;
    		}
    	}
    
    	cout << answer;
    }

     

     

    반응형

    '문제풀이 > 백준oj' 카테고리의 다른 글

    [백준OJ] 1520번 내리막 길  (0) 2021.09.16
    [백준OJ] 5547번 일루미네이션  (0) 2021.09.15
    [백준OJ] 8983번 사냥꾼  (0) 2021.09.14
    [백준OJ] 6443번 애너그램  (0) 2021.09.13
    [백준OJ] 7569번 토마토  (0) 2021.09.12

    댓글