1806 - 부분합
본문
$10\,000$ 이하의 자연수로 이루어진 길이 $N$짜리 수열이 주어진다. 이 수열에서 연속된 수들의 부분합 중에 그 합이 $S$ 이상이 되는 것 중, 가장 짧은 것의 길이를 구하는 프로그램을 작성하시오.
입력
첫째 줄에 $N$ ($10 \leq N < 100\,000$)과 $S$ ($0 < S \leq 100\,000\,000$)가 주어진다. 둘째 줄에는 수열이 주어진다. 수열의 각 원소는 공백으로 구분되어져 있으며, $10\,000$이하의 자연수이다.
출력
첫째 줄에 구하고자 하는 최소의 길이를 출력한다. 만일 그러한 합을 만드는 것이 불가능하다면 0
을 출력하면 된다.
제한
시간 제한 | 메모리 제한 |
---|---|
0.5sec | 128MB |
풀이
문제의 제목은 부분합인데 실제로는 연속합을 구하는 문제이다. 투 포인터를 활용하면 쉽게 해결할 수 있는 문제이다.
시작점에 양 끝 포인터를 가져다 두고, 그 사이의 합을 기록해둔다. 그 값을 $d$라고 할 때, 아래와 같은 절차만으로도 문제를 해결할 수 있다.
- $d < S$인 경우 : 오른쪽 포인터를 1칸 뒤로 이동시킨다
- $d \geq S$인 경우 : 구간의 길이를 정답의 후보로 기록한다. 왼쪽 포인터를 1칸 뒤로 이동시킨다
사실 설명은 이것만으로도 끝난다. 문제에서 원하는 바를 if-else 하나로 해결할 수 있는 문제.
- 참고 알고리즘 : 투 포인터
코드
사용 언어 : C
최종 수정일 : 2024 / 3 / 5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <stdio.h>
#define MAX_IDX 100000
int arr[MAX_IDX];
int n;
int sum, s;
int l, r;
int result = MAX_IDX + 1;
#define min(a, b) (((a) > (b)) ? (b) : (a))
int main() {
scanf("%d %d", &n, &s);
for (int i = 0; i < n; ++i) {
scanf("%d", arr + i);
}
while (r < (n + 1)) {
if (sum >= s) {
result = min(result, r - l);
sum -= arr[l++];
} else {
sum += arr[r++];
}
}
if (result > MAX_IDX) {
printf("0");
} else {
printf("%d", result);
}
return 0;
}