본문 바로가기

Problem Solving/BaekJoon

1806 부분합

 

 

1806번: 부분합

첫째 줄에 N (10 ≤ N < 100,000)과 S (0 < S ≤ 100,000,000)가 주어진다. 둘째 줄에는 수열이 주어진다. 수열의 각 원소는 공백으로 구분되어져 있으며, 10,000이하의 자연수이다.

www.acmicpc.net

 

배열의 연속된 부분합 중, 합이 S 이상이 되는 가장 짧은 부분의 길이를 구하는 문제이다.

일단 분류는 투 포인터로 되어있는데 난 그냥 이진 탐색 써서 풀었다.

 

먼저 각 구간의 누적합을 계산한 다음, 배열의 첫번째 위치부터 n - 1번째 위치를 구간의 시작점으로 두고,

구간의 끝점은 이진 탐색으로 찾았는데, 끝점이 될 수 있는 left bound는 lbound, right bound는 rbound로 정하고

lbound와 rbound 사이의 거리를 좁혀가는 식으로 이진 탐색을 수행했다. 

 

일단 나는 그냥 문제 풀때 이진 탐색이 생각나서 이렇게 풀기는 했는데,

솔직히 그냥 투 포인터로 푸는게 코드도 간결하고 조금 더 빠르니 이 코드는 참고만 하는 게 좋을 것 같다.

 

 

PS는 양치기가 기본으로 되어야 제대로 된 방식으로 빠르게 문제 풀 수 있을 텐데 갈 길이 멀기만 하다 ㅜㅜ

 

C++

더보기
#include <iostream>
#include <vector>

using namespace std;

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

	int n, s;
	cin >> n >> s;

	vector<int> vec(n);
	vector<int> sum(n + 1);

	sum[0] = 0;
	for (int i = 0; i < n; ++i) {
		cin >> vec[i];
		sum[i + 1] = sum[i] + vec[i];
	}
	
	if (sum[n] < s)
		cout << 0;
	else {
		int res = n;
		for (int i = 0; i <= n && sum[n] - sum[i] >= s; ++i) {
			int lbound = i, rbound = n, mid;
			while (rbound >= lbound) {
				mid = (rbound - lbound) / 2 + lbound;
				if (sum[mid] - sum[i] == s) {
					if (mid - i < res)
						res = mid - i;
					break;
				}
				else if (sum[mid] - sum[i] > s) {
					if (mid - i < res)
						res = mid - i;
					rbound = mid - 1;
					continue;
				}
				lbound = mid + 1;
			}
		}
		cout << res;
	}
	return 0;
}
728x90

'Problem Solving > BaekJoon' 카테고리의 다른 글

2056 작업  (0) 2021.02.06
1987 알파벳  (0) 2021.02.02
2228 구간 나누기  (0) 2021.01.15
4386 별자리 만들기  (0) 2021.01.15
2624 동전 바꿔주기  (0) 2021.01.12