그리디 알고리즘

을 사용하는 문제였다.

일단 시간제한이 2초인데, 입력값이 (위치, 인구수) 쌍으로 10만개이다. 이를 일반적인 브루트포스로 풀게되면 전체 평균을 구하는 과정 중에 값의 범위 때문에 터질 수도 있다. 다만 시간으로는 안 터지지 않을까 싶다.

즉, 이 문제의 경우 그리디하게 위치를 정해주어야 하는데 그 로직은 다음과 같다.

  1. 입력받은 쌍을 위치 순으로 정렬한다.
  2. 해당 위치까지의 누적합을 배열에 저장해둔다.
  3. 그 후 이분탐색으로 왼쪽 누적합, 오른쪽 누적합의 차이가 최소인 지점을 찾는다.

생각보다 간단한 로직이다. 허나 평균을 구하는게 아닌 누적합 자체로 이분탐색을 한다는 것 자체가 생각하기 어렵기 때문에 경험이 필요한 문제라 생각한다.

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <cstdio>
#include <tuple>
#include <string>
#include <string.h>
#include <stack>
#include <set>
#include <map>


using namespace std;
typedef long long LL;

LL x[100001];
LL a[100001];

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	
	int n;
	vector<pair<LL, LL>> v;
	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> x[i] >> a[i];
		v.push_back({ x[i], a[i] });
	}
	sort(v.begin(), v.end());

	vector<LL> sum;
	sum.push_back(v[0].second);
	for (int i = 1; i < n; i++) {
		sum.push_back(sum[i - 1] + v[i].second);
	}

	LL left = 0, right = n, mid;
	LL pos = 100000;
	while (left <= right) {
		mid = (left + right) / 2;
		if (sum[mid] < sum[n - 1] - sum[mid]) {
			left = mid + 1;
		}
		else if (sum[mid] > sum[n - 1] - sum[mid]) {
			right = mid - 1;
			pos = min(pos, v[mid].first);
		}
	}
	cout << pos;
	return 0;
}
 

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

 

2285번: 우체국

첫째 줄에 N(1 ≤ N ≤ 100,000)이 주어진다. 다음 N개의 줄에는 X[1] A[1], X[2] A[2], …, X[N] A[N]이 주어진다. 범위는 |X[i]| ≤ 1,000,000,000, 0 ≤ A[i] ≤ 1,000,000,000 이며 모든 입력은 정수이다. 모든 A[i]를 합

www.acmicpc.net

 

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

[백준-2239] 스도쿠  (0) 2021.08.18
[백준-2357] 최솟값과 최댓값  (0) 2021.08.16
[백준-10943] 팰린드롬?  (0) 2021.08.15
[백준-2407] 조합  (0) 2021.08.13