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

 

이번에 볼 문제는 백준 28068번 문제인 I Am Knowledge이다.
문제는 아래 링크를 확인하자.

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

 

28068번: I Am Knowledge

저택에 살고 있는 마법사는 지하의 도서관에 자주 방문한다. 어느 날, 마법사는 도서관에 있는 책 N권을 모두 읽기로 했다. 책은 한 번에 한 권씩만 읽을 수 있지만, 책을 읽는 순서는 마음대

www.acmicpc.net

 

각 책을 (a,b)와 같이 나타낸다면, 해당 책은 마법사의 즐거움이 a 이상일 때 읽어 즐거움을 b-a만큼 증가시켜줄 수 있다. (단, b-a가 음수이면 a-b만큼 감소한다.) 모든 책을 읽는 방법이 존재한다면 순서를 적절히 조절해 '책을 읽기 전과 비교했을 때 읽은 뒤 즐거움이 증가하는 책'들을 모두 읽고 그렇지 않은 책들을 마저 읽어 모든 책을 읽을 수도 있음을 관찰하자.

 

읽은 뒤 즐거움이 증가하는 책들을 조건을 만족하도록 전부 읽는 것이 가능한지는 그러한 책들을 a값을 기준으로 오름차순 정렬했을 때 이 책들을 그 순서대로 읽어나갈 수 있는지를 확인하는 것으로 해낼 수 있다.

 

읽은 뒤 즐거움이 감소하는 책들을 차례대로 읽을 수 있는지를 생각해보자. 만약 그러한 방법이 존재한다면 모든 책을 다 읽었을 때의 최종 즐거움 값은 (모든 b의 값의 합) - (모든 a의 값의 합)이 될 것이다. 이 즐거움 값에서 시작해 즐거움이 감소하는 책을 읽어나가던 과정을 거꾸로 실행해나가는 것은 '현재 즐거움 값이 b 이상일 때 읽어 즐거움을 a-b(>0)만큼 증가시키는' 책을 읽어나가는 것으로 생각할 수 있다. 이것이 앞선 문단의 경우와 동일함을 관찰하면 이 또한 같은 방법으로 해결할 수 있음을 알 수 있다.

 

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

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;

int N;
vector<pair<int, int>> vec1, vec2;
ll val1, val2;

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

	cin >> N;
	while (N--) {
		int a, b; cin >> a >> b;
		val1 += (b - a);
		if (a > b) vec1.emplace_back(make_pair(b, a - b));
		else vec2.emplace_back(make_pair(a, b - a));
	}

	sort(vec1.begin(), vec1.end());
	sort(vec2.begin(), vec2.end());

	for (auto& p : vec1) {
		if (val1 < p.first) {
			cout << 0;
			return 0;
		}
		val1 += p.second;
	}

	for (auto& p : vec2) {
		if (val2 < p.first) {
			cout << 0;
			return 0;
		}
		val2 += p.second;
	}

	cout << 1;
}
728x90

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

 

이번에 볼 문제는 백준 28067번 문제인 기하가 너무 좋아이다.
문제는 아래 링크를 확인하자.

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

 

28067번: 기하가 너무 좋아

기하를 좋아하는 성우는 가로 길이가 N, 세로 길이가 M인 직사각형 모양의 마당을 샀다. 성우는 특히 삼각형을 좋아하기 때문에, 이 마당에 삼각형 모양의 울타리를 지으려고 한다. 울타리

www.acmicpc.net

가능한 세 점의 쌍은 순서쌍 ((a,d),(b,e),(c,f))와 같이 나타낼 수 있다. 각 변수 a,b,c,d,e,f는 0 이상 10 이하이므로 이와 같은 모든 순서쌍의 개수는 116=1771561가지이다.

 

각 순서쌍에 대하여 해당 순서쌍이 (1) 삼각형을 나타내는지 확인 후 (2) 해당 삼각형과 대응되는, 즉 합동이면 같은 값을 갖고 그렇지 않다면 다른 값을 갖는 변수를 이용해 개수를 세어 문제를 해결하자.

 

(2)의 판단 기준으로 글쓴이는 변의 길이를 이용한다. 두 삼각형의 세 변의 길이가 같다는 것과 두 삼각형은 합동(SSS합동)임이 동치임은 잘 알려져있다. 이에 따라 두 삼각형의 세 변의 길이'의 제곱'이 같은 것과 두 삼각형이 합동인 것은 동치라고 말할 수 있다. 따라서 위에서 정의한 변수 a,b,c,d,e,f를 이용하면 세 변의 길이의 제곱을 간단히 계산할 수 있고, 이들을 크기순으로 나열하면 합동인 두 삼각형은 같은 나열을 갖게 될 것임을 알 수 있다. 이와 같은 나열의 가짓수를 계산해 문제를 해결하자.

 

글쓴이는 해당 나열을 200진법의 정수로 생각(문제 제약조건상 변의 길이의 제곱은 1 이상 200 이하의 값임을 이용)해 해당 나열을 정수에 다시 대응시켜 문제를 해결하였다.

 

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

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int N, M;
bool visited[8000001];
int cnt;

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

	cin >> N >> M;
	for (int a = 0; a <= N; a++) {
		for (int b = a; b <= N; b++) {
			for (int c = b; c <= N; c++) {
				for (int d = 0; d <= M; d++) {
					for (int e = 0; e <= M; e++) {
						for (int f = 0; f <= M; f++) {
							if ((b - a) * (f - d) == (e - d) * (c - a)) continue; // 삼각형이 아님

							int dx1 = b - a, dx2 = c - b, dx3 = a - c, dy1 = e - d, dy2 = f - e, dy3 = d - f;
							dx1 *= dx1, dx2 *= dx2, dx3 *= dx3, dy1 *= dy1, dy2 *= dy2, dy3 *= dy3;
							int X = dx1 + dy1, Y = dx2 + dy2, Z = dx3 + dy3;
							vector<int> vec = { X - 1,Y - 1,Z - 1 };
							sort(vec.begin(), vec.end());

							int val = vec[0] * 40000 + vec[1] * 200 + vec[2];
							if (visited[val]) continue;
							visited[val] = 1;
							cnt++;
						}
					}
				}
			}
		}
	}

	cout << cnt;
}
728x90

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

 

이번에 볼 문제는 백준 28066번 문제인 타노스는 요세푸스가 밉다이다.
문제는 아래 링크를 확인하자.

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

 

28066번: 타노스는 요세푸스가 밉다

$N$마리의 청설모가 $1$번부터 $N$번까지 순서대로 시계 방향으로 원을 이루면서 앉아있다. 타노스는 손을 튕겨서 순서대로 두 번째 청설모를 제거해 왔는데, 옆 나라의 수학자 요세푸스도 이미

www.acmicpc.net

문제에서 주어지는 내용을 직접 시뮬레이션하는 코드를 작성하자. 큐(queue) 자료구조에 1부터 N까지의 청설모를 차례대로 넣고, 이번 과정에서 다룰 K마리를 큐에서 접근하면 주어진 내용을 빠르게 시뮬레이션할 수 있다.

 

구체적으로, 큐의 첫 번째 원소가 "첫 번째 청설모"일 때, 첫 번째 청설모를 저장한 다음 큐에서 K마리(남은 청설모가 K보다 적다면 남은 마릿수)만큼 큐에서 청설모를 제거하고 첫 번째 청설모를 큐에 새로 추가하면 다음 "첫 번째 청설모"가 큐의 맨 앞에 있는 상태로 만들 수 있다. 이를 반복해 문제를 해결하자.

 

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

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

int N, K;
queue<int> que;

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

	cin >> N >> K;
	for (int i = 1; i <= N; i++) que.push(i);

	while (que.size() > 1) {
		int kp = que.front();
		int itercnt = min(K, (int)que.size());
		for (int i = 0; i < itercnt; i++) que.pop();
		que.push(kp);
	}

	cout << que.front();
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 28068 // C++] I Am Knowledge  (0) 2023.11.30
[BOJ 28067 // C++] 기하가 너무 좋아  (0) 2023.11.29
[BOJ 28065 // C++] SW 수열 구하기  (1) 2023.11.27
[BOJ 28064 // C++] 이민희진  (2) 2023.11.26
[BOJ 28063 // C++] 동전 복사  (2) 2023.11.25

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

 

이번에 볼 문제는 백준 28065번 문제인 SW 수열 구하기이다.
문제는 아래 링크를 확인하자.

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

 

28065번: SW 수열 구하기

A=[4,1,3,2]라고 하자. |A2A1|=3, |A3A2|=2, |A4A3|=1이다. 이는 조건에 맞고, 따라서 수열 A는 SW 수열이다.

www.acmicpc.net

1부터 시작해 지금까지 사용하지 않은 가장 차가 큰 수를 반복해 나열해 얻을 수 있는 수열을 생각해보자. 이 수열의 계차의 절댓값을 나열하면 N-1, N-2, N-3, ..., 1과 같이 단조감소하는 것을 알 수 있다. 이는 문제에서 요구하는 성질을 만족하므로 이 수열은 문제의 답 중 하나가 된다.

 

위와 같은 수열을 생성하는 코드를 작성해 문제를 해결하자. 사용하지 않은 수 중 가장 큰 수 및 가장 작은 수를 탐색하는 O(N) 알고리즘을 이용해도 제한시간 내로 충분히 문제를 해결할 수 있다. 아래와 같이 다음 가장 큰 수 및 가장 작은 수를 저장하는 L, R과 같은 변수를 이용해도 좋다.

 

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

#include <iostream>
using namespace std;

int N;
int L, R;

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

	cin >> N;
	L = 1, R = N;
	for (; L < R; L++, R--) cout << L << ' ' << R << ' ';
	if (L == R) cout << L;
}
728x90

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

 

이번에 볼 문제는 백준 28064번 문제인 이민희진이다.
문제는 아래 링크를 확인하자.

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

 

28064번: 이민희진

첫 줄에 연결할 수 있는 서로 다른 사람 쌍의 개수를 출력한다.

www.acmicpc.net

두 이름 s1과 s2가 있을 때, 두 이름이 연결가능한지를 판단할 수 있다면 이를 N(N-1)/2가지 순서쌍에 적용해보는 것으로 문제를 해결할 수 있을 것이다. 이 판단방법을 생각해보자.

 

두 문자열의 공통 부분 길이 len이 될 수 있는 정수는 1 이상 min(s1의 길이, s2의 길이) 이하이다. 각 후보 len에 대하여 s1의 앞 len개 문자로 구성된 문자열과 s2의 뒷 len개 문자로 구성된 문자열이 같은지, 그리고 s2의 앞 len개 문자로 구성된 문자열과 s2의 앞 len개 문자로 구성된 문자열이 같은지를 각각 확인해 하나라도 같아면 두 문자열을 이어붙일 수 있음을 알 수 있다. 또한 그렇지 않다면 이어붙일 수 없음을 알 수 있다. 이를 이용해 문제를 해결하자.

 

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

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

int N;
string s[100];

int ans;

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

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

	for (int i = 0; i < N; i++) {
		string& s1 = s[i];
		int s1len = s1.length();
		for (int j = i + 1; j < N; j++) {
			string& s2 = s[j];
			int s2len = s2.length();
			int len = min(s1len, s2len);
			bool chk = 0;
			for (int l = 1; l <= len; l++) {
				if (s1.substr(0, l) == s2.substr(s2len - l, l)) chk = 1;
				if (s2.substr(0, l) == s1.substr(s1len - l, l)) chk = 1;
			}

			if (chk) ans++;
		}
	}

	cout << ans;
}
728x90

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

 

이번에 볼 문제는 백준 28063번 문제인 동전 복사이다.
문제는 아래 링크를 확인하자.

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

 

28063번: 동전 복사

돈이 없어 슬픈 레이무는 어느 날, 한 기계를 발견했다. 이 기계는 한 변의 길이가 N인 정사각형 모양이고, 1×1 크기의 정사각형 칸들로 이루어져 있다. 각 칸의 위치는 좌표로 나타낼

www.acmicpc.net

동전의 초기 위치가 왼쪽 변에 맞닿아있다면 기계를 왼쪽으로 조작할 필요가 없고 그렇지 않다면 기계를 왼쪽으로 조작해야 함을 관찰하자.

 

이는 다른 변들과 대응되는 방향에 대하여 동일하게 적용된다. 이를 이용해 문제의 답을 구하는 코드를 작성해 문제를 해결하자.

 

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

#include <iostream>
using namespace std;

int N, x, y;
int ans = 4;

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

	cin >> N >> x >> y;
	if (x == 1) ans--;
	if (x == N) ans--;
	if (y == 1) ans--;
	if (y == N) ans--;

	cout << ans;
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 28065 // C++] SW 수열 구하기  (1) 2023.11.27
[BOJ 28064 // C++] 이민희진  (2) 2023.11.26
[BOJ 28062 // C++] 준석이의 사탕 사기  (1) 2023.11.24
[BOJ 28061 // C++] 레몬 따기  (0) 2023.11.23
[BOJ 28281 // C++] 선물  (0) 2023.11.22

+ Recent posts