[백준 C++] 1806번 부분합
백준 1806번 부분합 cpp c++로 풀이
[백준 C++] 1806번 부분합
1806번: 부분합
문제 요약
문제
10,000 이하의 자연수로 이루어진 길이 N짜리 수열이 주어진다. 이 수열에서 연속된 수들의 부분합 중에 그 합이 S 이상이 되는 것 중, 가장 짧은 것의 길이를 구하는 프로그램을 작성하시오.
사용 알고리즘
투포인터, 누적합
입출력
- 입력:
- 출력: ``` 예제1
입력 첫째 줄에 N (10 ≤ N < 100,000)과 S (0 < S ≤ 100,000,000)가 주어진다. 둘째 줄에는 수열이 주어진다. 수열의 각 원소는 공백으로 구분되어져 있으며, 10,000이하의 자연수이다. 출력 첫째 줄에 구하고자 하는 최소의 길이를 출력한다. 만일 그러한 합을 만드는 것이 불가능하다면 0을 출력하면 된다.
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
## 풀이
먼저 누적합을 사용하여 전체 누적합을 다 구한다. 이후 투포인터를 사용하는데 한개는 맨 앞, 한개는 그 바로 뒤에서 시작한다. 크기가 s보다 작으면 뒤의 포인터를 뒤로 보내고, s보다 크면 앞의 포인터를 뒤로 보낸다. 부분합은 누적합을 이용하여 쉽게 구한다. 만약 뒤의 포인터가 끝을 벗어난다면 그대로 끝내면된다. 그 상황에서 앞의 포인터가 뒤로 가도 s보다 커질 수 없기 때문이다.
## 어려웠던 점
투포인터를 시작할때 모두 앞에 두고 시작해야한다.
## 배운 점 / 느낀 점
투포인터를 사용한지 얼마 되지 않아 아이디어를 떠올리는데 오래걸렸다. 투포인터를 자유자재로 사용하기 위해 더 노력해야겠다.
## 전체 코드
```cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int n, s, m;
vector<int> sss;
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
cin >> n >> s;
sss = vector<int>(n+1,0);
m = n+1;
for (int i = 1; i < n+1; i++) {
cin >> sss[i];
sss[i] += sss[i-1];
}
int l = 0;
int r = 1;
while(r < n+1){
if(sss[r]-sss[l] >= s){
m = min(m, r-l);
l += 1;
}
else{
r += 1;
}
}
if(m == n+1){
cout << 0;
}
else cout << m;
return 0;
}
This post is licensed under CC BY 4.0 by the author.