※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 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

※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 1593번 문제인 문자 해독이다.
문제는 아래 링크를 확인하자.

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

 

1593번: 문자 해독

첫째 줄에 고고학자들이 찾고자 하는 단어 W의 길이 g와 발굴된 벽화에서 추출한 문자열 S의 길이 |S|가 빈 칸을 사이에 두고 주어진다. (1≤g≤3000,  g≤|S|≤3,000,000) 둘째 줄에 W, 셋째 줄에 S의 실

www.acmicpc.net

찾고자 하는 단어를 W라 하고, W를 찾으려는 문자열을 S라 하자.

이 문제는 S의 각 W길이의 부분문자열에 포함된 문자구성이 W와의 문자구성과 같은지를 판단하는 문제이다.

 

[a,b] 구간의 부분문자열의 구성과 [a+1,b+1] 구간의 부분문자열 구성을 살펴보자.

두 문자를 제외하고 모두 일치한다는 것을 알 수 있다.

그렇다는 것은, 문자구성을 계산할 때 중복된 부분에 대한 작업을 새로 하지 않고 재활용할 수 있는 방식을 떠올린다면 이 문제를 쉽게 해결할 수 있다는 뜻이 된다.

 

글쓴이는 각 W의 길이 부분문자열에 대하여 불일치도 chk를 만들어 점화식을 세워 문제를 풀었다.

 

아래는 제출한 소스코드이다.

#include <iostream>
#include <string>
using namespace std;

int cnt[128];

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

	int s1len, s2len; cin >> s1len >> s2len;

	string s1, s2; cin >> s1 >> s2;
	for (int i = 0; i < s1len; i++) cnt[s1[i]]++;

	int chk = s1len, ans = 0; // chk: 현재 불일치도
	for (int i = 0; i < s1len; i++) {
		if (cnt[s2[i]] > 0) chk--;
		else chk++;
		cnt[s2[i]]--;
	}
	if (chk == 0) ans++;

	for (int i = s1len; i < s2len; i++) {
		int L = i - s1len;
		if (cnt[s2[L]] < 0) chk--;
		else chk++;
		cnt[s2[L]]++;

		if (cnt[s2[i]] > 0) chk--;
		else chk++;
		cnt[s2[i]]--;

		if (chk == 0) ans++;
	}

	cout << ans;
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 1043 // C++] 거짓말  (0) 2021.06.04
[BOJ 1208 // C++] 부분수열의 합 2  (0) 2021.06.03
[BOJ 5054 // C++] 주차의 신  (0) 2021.06.01
[BOJ 10807 // C++] 개수 세기  (0) 2021.06.01
[BOJ 11098 // C++] 첼시를 도와줘!  (0) 2021.06.01

※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 5054번 문제인 주차의 신이다.
문제는 아래 링크를 확인하자.

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

 

5054번: 주차의 신

첫째 줄에 테스트 케이스의 개수 t가 주어진다. (1 ≤ t ≤ 100) 모든 테스트 케이스는 두 줄로 이루어져 있다. 첫째 줄에는 선영이가 방문할 상점의 수 n이 주어지며 (1 ≤ n ≤ 20), 둘째 줄에는 상점

www.acmicpc.net

어디에 주차하더라도 가장 왼쪽 상점과 가장 오른쪽 상점을 들러야 한다는 점에 주목해보자.

최단거리로 모든 상점을 들리려면 ((가장 오른쪽 상점) - (가장 왼쪽 상점)) * 2의 거리만큼을 걸어야 한다는 하다는 것을 알 수 있다.

 

아래는 제출한 소스코드이다.

#include <iostream>
using namespace std;

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

	int T; cin >> T;
	while (T--) {
		int N; cin >> N;
		int mx = 0, mn = 100;
		while (N--) {
			int x; cin >> x;
			if (x > mx) mx = x;
			if (x < mn) mn = x;
		}
		cout << (mx - mn) * 2 << '\n';
	}
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 1208 // C++] 부분수열의 합 2  (0) 2021.06.03
[BOJ 1593 // C++] 문자 해독  (0) 2021.06.02
[BOJ 10807 // C++] 개수 세기  (0) 2021.06.01
[BOJ 11098 // C++] 첼시를 도와줘!  (0) 2021.06.01
[BOJ 14624 // C++] 전북대학교  (0) 2021.06.01

※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 10807번 문제인 개수 세기이다.
문제는 아래 링크를 확인하자.

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

 

10807번: 개수 세기

첫째 줄에 정수의 개수 N(1 ≤ N ≤ 100)이 주어진다. 둘째 줄에는 정수가 공백으로 구분되어져있다. 셋째 줄에는 찾으려고 하는 정수 v가 주어진다. 입력으로 주어지는 정수와 v는 -100보다 크거

www.acmicpc.net

글쓴이는 입력으로 주어지는 정수의 절댓값이 100 이하이므로 0~200의 정수에 입력으로 들어오는 -100~100의 정수를 대응시켜 개수를 세어주었다.

 

아래는 제출한 소스코드이다.

#include <iostream>
using namespace std;

int arr[201];

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

	int N; cin >> N;
	while (N--) {
		int x; cin >> x;
		arr[x + 100]++;
	}
	int v; cin >> v;
	cout << arr[v + 100];
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 1593 // C++] 문자 해독  (0) 2021.06.02
[BOJ 5054 // C++] 주차의 신  (0) 2021.06.01
[BOJ 11098 // C++] 첼시를 도와줘!  (0) 2021.06.01
[BOJ 14624 // C++] 전북대학교  (0) 2021.06.01
[BOJ 1408 // C++] 24  (0) 2021.06.01

※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 1173번 문제인 운동이다.
문제는 아래 링크를 확인하자.

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

 

11098번: 첼시를 도와줘!

구단이 성적을 내지 못한다면 답은 새 선수 영입뿐이다. 이것은 오늘날 유럽 리그에서 가장 흔한 전략이고, 노르웨이의 로젠버그 팀은 이러한 전략이 성공한 대표적 예시다. 그들은 많은 스카

www.acmicpc.net

이 문제에서는 가격과 이름이 쌍으로 주어질 때, 가장 비싼 선수의 이름을 출력하는 문제이다.

가장 비싼 선수의 이름만 필요하므로, 입력을 받으면서 가장 비싼 가격이 갱신될 때마다 이름을 바꿔 저장하는 것으로 문제를 해결할 수 있다.

 

아래는 제출한 소스코드이다.

#include <iostream>
#include <string>
using namespace std;

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

	int T; cin >> T;
	while (T--) {
		int price = 0; string name;
		int p; cin >> p;
		while (p--) {
			int x; string s; cin >> x >> s;
			if (x > price) price = x, name = s;
		}

		cout << name << '\n';
	}
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 5054 // C++] 주차의 신  (0) 2021.06.01
[BOJ 10807 // C++] 개수 세기  (0) 2021.06.01
[BOJ 14624 // C++] 전북대학교  (0) 2021.06.01
[BOJ 1408 // C++] 24  (0) 2021.06.01
[BOJ 5635 // C++] 생일  (0) 2021.06.01

※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 14624번 문제인 전북대학교이다.
문제는 아래 링크를 확인하자.

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

 

14624번: 전북대학교

전북대학교의 심볼은 균형과 조화, 지성과 이상을 향한 방향성과 목표를 나타낸다. 절제된 한국적 아름다움을 꾸밈없는 소박함과 여백을 통해 시각화하였으며, 심볼의 방향에 따라 한국적인 대

www.acmicpc.net

N을 읽어, N이 짝수면 주어진 문자열을, 홀수면 첫 줄에 N개의 별을, 두번째 줄부터는 보이는 대로 별을 찍으면 된다.

 

아래는 제출한 소스코드이다.

#include <iostream>
using namespace std;

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

	int N; cin >> N;
	if (N & 1) {
		for (int i = 0; i < N; i++) cout << '*';
		cout << '\n';

		int mid = N / 2;
		for (int j = 0; j < mid; j++) cout << ' ';
		cout << '*' << '\n';
		for (int i = 1; i <= mid; i++) {
			for (int j = 0; j < mid - i; j++) cout << ' ';
			cout << '*';
			for (int j = mid - i + 1; j < mid + i; j++) cout << ' ';
			cout << '*' << '\n';;
		}
	}
	else cout << "I LOVE CBNU";
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 10807 // C++] 개수 세기  (0) 2021.06.01
[BOJ 11098 // C++] 첼시를 도와줘!  (0) 2021.06.01
[BOJ 1408 // C++] 24  (0) 2021.06.01
[BOJ 5635 // C++] 생일  (0) 2021.06.01
[BOJ 2711 // C++] 오타맨 고창영  (0) 2021.06.01

+ Recent posts