뜌릅

부분수열의 합2 1208번 [백준] 본문

알고리즘/PS 문제

부분수열의 합2 1208번 [백준]

TwoCastle9 2021. 11. 2. 19:38
반응형

오랜만에 백준 문제를 풀어 보았다. meet in the middle이라는 기법을 활용하여 푸는 문제이다.

meet in the middle이라는 기법을 처음 접해 보았는데, 부분수열의 합1에서 모든 경우의 수를 구하여 풀었던 것을 같이 활용하여 문제를 풀 수 있었다.

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define fast_io ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define rep(i, j) for(int i=0;i<j;i++)
#define mrep(i,j,k) for(int i = j; i<=k;i++)
#define drep(i,j,k) for(int i = j; i>=k; i--)
typedef long long ll;


int main() {
	//#ifndef ONLINE_JUDGE
	//    freopen("input.txt", "r", stdin);
	//#endif
	fast_io;
	int N, S;
	cin >> N >> S;
	vector<int> v(N);
	rep(i, N)cin >> v[i];
	int half = N / 2;
	vector<int> first(1 << (N - half));
	for (int i = 0; i < 1 << (N - half); i++) {//calculate all the case1
		for (int j = 0; j < N - half; j++) {
			if (i & (1 << j))first[i] += v[j];
		}
	}
	vector<int> second(1 << half);
	for (int i = 0; i < 1 << half; i++) {//calculate all the case2
		for (int j = 0; j < half; j++) {
			if (i & (1 << j))second[i] += v[j + (N - half)];
		}
	}
	ll result = 0;
	sort(first.begin(), first.end());
	sort(second.begin(), second.end(),greater<int>());
	ll idx = 0, idx2 = 0;
	while (idx < 1 << (N - half)&& idx2 < 1 << half) {//point to point algorithm
		if (first[idx] + second[idx2] == S) {
			ll cnt1 = 1, cnt2 = 1;
			idx++;
			idx2++;
			while (idx < 1 << (N - half) && first[idx] == first[idx - 1]) {
				idx++;
				cnt1++;
			}
			while (idx2 < 1 << half && second[idx2] == second[idx2 - 1]) {
				idx2++;
				cnt2++;
			}
			result += cnt1 * cnt2;
		}
		else if (first[idx] + second[idx2] > S) {
			idx2++;
		}
		else if (first[idx] + second[idx2] < S) {
			idx++;
		}
	}
	if (S == 0)result--;
	cout << result;
	return 0;
}

https://www.acmicpc.net/problem/1208

반응형

'알고리즘 > PS 문제' 카테고리의 다른 글

외판원 순회 2098번 [백준]  (0) 2021.12.22
Subsequence (부분합) 1806번 [백준]  (0) 2021.11.04
음악프로그램 2623번 [백준]  (0) 2021.07.01
내려가기 2096번 [백준]  (0) 2021.06.20
트리의 순회 2263번 [백준]  (2) 2021.05.27