※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※
이번에 볼 문제는 백준 1208번 문제인 부분수열의 합 2이다.
문제는 아래 링크를 확인하자.
https://www.acmicpc.net/problem/1208
1208번: 부분수열의 합 2
첫째 줄에 정수의 개수를 나타내는 N과 정수 S가 주어진다. (1 ≤ N ≤ 40, |S| ≤ 1,000,000) 둘째 줄에 N개의 정수가 빈 칸을 사이에 두고 주어진다. 주어지는 정수의 절댓값은 100,000을 넘지 않는다.
www.acmicpc.net
2^20의 값이 대충 100만이므로, 주어진 정수를 두개의 집합으로 나누어 가능한 부분수열의 합을 모두 구하고 다시 합치는 Meet in the Middle 전략으로 이 문제를 해결할 수 있다.
각 집합에서 나올 수 있는 부분수열의 합은 약 100만가지이고, 나올 수 있는 각 합을 정렬한 뒤 보관하면 각 집합의 부분수열의 개수에 비례한 선형시간으로 답을 구해낼 수 있기 때문이다.
이때, 각 집합에 담은 부분수열의 합들 중에도 구하는 합과 일치하는 값이 있을 수 있다는 점에 유의하자.
아래는 제출한 소스코드이다.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int arr[40];
vector<int> sum1, sum2;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
int N, S; cin >> N >> S;
for (int i = 0; i < N; i++) cin >> arr[i];
if (N == 1) {
if (arr[0] == S) cout << 1;
else cout << 0;
return 0;
}
int mid = N / 2;
long long sum1cnt = 0;
if (arr[0] == S) sum1cnt++;
sum1.push_back(arr[0]);
for (int i = 1; i < mid; i++) {
int current = arr[i];
int vecsize = sum1.size();
for (int k = 0; k < vecsize; k++) {
int temp = current + sum1[k];
if (temp == S) sum1cnt++;
sum1.push_back(temp);
}
if (current == S) sum1cnt++;
sum1.push_back(current);
}
long long sum2cnt = 0;
if (arr[mid] == S) sum2cnt++;
sum2.push_back(arr[mid]);
for (int i = mid + 1; i < N; i++) {
int current = arr[i];
int vecsize = sum2.size();
for (int k = 0; k < vecsize; k++) {
int temp = current + sum2[k];
if (temp == S) sum2cnt++;
sum2.push_back(temp);
}
if (current == S) sum2cnt++;
sum2.push_back(current);
}
sort(sum1.begin(), sum1.end());
sort(sum2.begin(), sum2.end());
long long ans = 0;
auto sum1pt = sum1.begin();
auto sum2pt = sum2.rbegin();
int sum1size = sum1.size(), sum2size = sum2.size();
while (sum1pt !=sum1.end() && sum2pt != sum2.rend()) {
int L = *sum1pt, R = *sum2pt, LR = L + R;
if (LR > S) sum2pt++;
else if (LR < S) sum1pt++;
else {
long long cntL = 0, cntR = 0;
while (sum1pt != sum1.end()) {
if (*sum1pt != L) break;
cntL++;
sum1pt++;
}
while (sum2pt != sum2.rend()) {
if (*sum2pt != R) break;
cntR++;
sum2pt++;
}
ans += cntL * cntR;
}
}
cout << ans + sum1cnt + sum2cnt;
}
728x90
'BOJ' 카테고리의 다른 글
[BOJ 1213 // C++] 팰린드롬 만들기 (0) | 2021.06.05 |
---|---|
[BOJ 1043 // C++] 거짓말 (0) | 2021.06.04 |
[BOJ 1593 // C++] 문자 해독 (0) | 2021.06.02 |
[BOJ 5054 // C++] 주차의 신 (0) | 2021.06.01 |
[BOJ 10807 // C++] 개수 세기 (0) | 2021.06.01 |