https://www.acmicpc.net/problem/1806
#include <iostream>
#include <vector>
#define INF 987654321
using namespace std;
vector<int> arr;
vector<int> prefix;
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int n, S;
int ans = INF;
cin >> n >> S;
arr.resize(n);
prefix.resize(n);
for (int i = 0; i < n; i++) {
cin >> arr[i];
if (!i) {
prefix[i] = arr[i];
} else {
prefix[i] = prefix[i - 1] + arr[i];
}
}
int s = 0;
int e = 0;
do {
int sum = s != 0 ? prefix[e] - prefix[s - 1] : prefix[e];
if (sum >= S) {
ans = min(ans, e - s + 1);
s++;
} else {
e++;
}
} while (s <= n - 1 && e <= n - 1);
if (ans == INF) {
cout << 0;
} else {
cout << ans;
}
return 0;
}
1. 문제
n의 길이의 수열과 숫자 s가 주어진다. 수열의 부분합이 s 이상이 되는 부분수열 중 가장 짧은 것의 길이를 구하라. 단, 해당하는 부분수열이 존재하지 않을 경우 0을 출력한다.
2. 풀이
최대 길이 10만의 수열에 시간 제한이 0.5초이므로 누적합을 사용하여 구한다.
for (int i = 0; i < n; i++) {
cin >> arr[i];
if (!i) {
prefix[i] = arr[i];
} else {
prefix[i] = prefix[i - 1] + arr[i];
}
}
우선 수열을 입력받으면서 누적합을 계산하여 저장해준다.
int s = 0;
int e = 0;
do {
int sum = s != 0 ? prefix[e] - prefix[s - 1] : prefix[e];
if (sum >= S) {
ans = min(ans, e - s + 1);
s++;
} else {
e++;
}
} while (s <= n - 1 && e <= n - 1);
인덱스 s부터 e까지의 합을 구하고, 이를 비교할 것이다. 해당 부분수열의 합을 구하고, 부분합이 S 이상인 수열을 찾았다면, 해당 수열의 길이를 갱신해주고, 최소 길이를 구하는 것이 목표이므로 s를 오른쪽으로 옮겨 수열의 길이를 줄인다.
만약 부분수열의 합이 S 이하일 경우 수열의 합을 늘려야 하므로 e를 옮겨준다.
if (ans == INF) {
cout << 0;
} else {
cout << ans;
}
만약 해당하는 부분수열을 찾았다면 ans를, 찾지 못했다면 0을 출력하면 정답을 구할 수 있다.
'Coding Test' 카테고리의 다른 글
백준 2110 공유기 설치 (C++) (0) | 2024.08.06 |
---|---|
백준 15664 N과 M(10) (C++) (0) | 2024.08.05 |
백준 20924 트리의 기둥과 기지 (C++) (0) | 2024.08.02 |
백준 2056 작업 (C++) (0) | 2024.08.01 |
백준 3107 IPv6 (C++) (0) | 2024.08.01 |