[백준] 1208_부분수열의 합 2 C++


알고보면 반으로 나눠보는 문제

정답제출코드


#include <iostream>
#include <map>
#include <algorithm>

using namespace std;

int N, S;
int arr[41];
map<int, int> total;
long long cnt = 0;

void leftSum(int s, int sum)
{
    if (s == N/2)
    {
        total[sum]++;
        return;
    }
    leftSum(s+1, sum);
    leftSum(s+1, sum+arr[s]);
}

void rightSum(int s, int sum)
{
    if (s == N)
    {
        cnt += total[S-sum];
        return;
    }
    rightSum(s+1, sum);
    rightSum(s+1, sum+arr[s]);
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    cin >> N >> S;

    for (int i = 0; i < N; ++i)
        cin >> arr[i];

    sort(arr, arr + N);

    leftSum(0, 0);
    rightSum(N/2, 0);

    if (S == 0)
        cout << cnt - 1;
    else
        cout << cnt;

    return 0;
}

참고링크를 참고해서 풀었다.


투 포인터인지, 이분 탐색인지 생각을 했지만,

어떻게 풀어야할지 감이 오지 않아서 검색을 해보았다.

이 문제의 취지는 시간복잡도가 O(2^40)이 나오는 것을 O(2^20 * 2)로 푸는 것이었다.

우선, 수들의 합과 그 경우의 수를 담을 map을 구성을 해준다.

map<int, int> total; // <수들의 합, 나오는 경우의 수>

왼쪽 부분은 개수를 저장을 하고,

오른쪽 부분은 구한 부분 수열의 합이 sum 이면 map[S-sum]의 값

왼쪽 부분에서 계산을 할 때, 합이 S-sum이었던 부분과 더하면 S가 만들어지기 때문에

결과값 cnt에 map[S-sum]을 더해준다.

이 때, S = 0이면 둘 다 공집합인 경우를 제외시킨다.


© 2022.07. by Wookey_Kim

Powered by Hydejack v7.5.2