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

 

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

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

 

4139번: Octagons

Below is a picture of an infinite hyperbolic tessellation of octagons. If we think of this as a graph of vertices (of degree three), then there exists an isomorphism of the graph which maps any vertex x onto any other vertex y. Every edge is given a label

www.acmicpc.net

같은 문자가 연속으로 등장("aa", "bb", cc")하는 경우 해당 부분을 문자열에서 지우더라도 문제의 답이 달라지지 않는다. 먼저 주어진 문자열 s에서 이러한 부분문자열을 지우자. 이 때, 문자열을 일부 지운 뒤 이어붙이는 과정에서 지우고자 하는 형태의 문자열이 다시 생길 수 있음에 유의하자. 만약 이렇게 얻은 문자열이 빈 문자열이라면 답은 "closed"가 된다.

 

현재 남은 문자열이 빈 문자열이 아니라 가정하자. 만약 이 문자열이 나타내는 곡선이 closed라면 해당 곡선 "내부"에서 팔각형을 하나 고를 수 있을 것이다. 그리고 다음과 같은 연산들을 적절하게 이용해 고른 팔각형을 문자열이 나타내는 곡선으로 변환할 수 있을 것이다(물론 문자열이 나타내는 곡선이 open이라면 불가능하다):

 

(1) "aa", "bb", "cc"의 삽입

(2) 부분문자열 "a"를 "bababab"로 변경 (과 같은 형태의 연산들)

(3) 부분문자열 "ab"를 "bababa"로 변경 (과 같은 형태의 연산들)

(4) 부분문자열 "aba"를 "babab"로 변경 (과 같은 형태의 연산들)

(5) 부분문자열 "abab"를 "baba"로 변경 (과 같은 형태의 연산들)

(6) 부분문자열 "ababa"를 "bab"로 변경 (과 같은 형태의 연산들)

(7) 부분문자열 "ababab"를 "ba"로 변경 (과 같은 형태의 연산들)

(8) 부분문자열 "abababa"를 "b"로 변경 (과 같은 형태의 연산들)

 

해당 변환과정은 내부의 팔각형을 주어진 곡선모양으로 "펼쳐나가는" 과정과 문자열 변환을 대응시켜 상상해보면 쉽게 이해할 수 있을 것이다.

 

따라서, 주어지는 문자열을 위의 규칙의 역과정만으로 변환해 빈 문자열로 만들 수 있는지를 확인하는 것으로 문제를 해결할 수 있다. "aa", "bb" 및 "cc"가 빈 문자열과 같다는 점을 잘 이용하면 직접 구현해 확인해야 할 경우의 수를 줄일 수 있으니 잘 생각해보자.

 

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

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

int T;
string S, s;

void func(string q) {
	for (auto& l : q) {
		s += l;
		int slen = s.length();
		if (s.length() > 1) {
			string ss = s.substr(slen - 2, 2);
			if (ss == "aa" || ss == "bb" || ss == "cc") {
				s = s.substr(0, slen - 2);
				continue;
			}
		}
		if (s.length() > 4) {
			string ss = s.substr(slen - 5, 5);
			if (ss == "ababa") {
				s = s.substr(0, slen - 5);
				func("bab");
			}
			else if (ss == "babab") {
				s = s.substr(0, slen - 5);
				func("aba");
			}
			else if (ss == "bcbcb") {
				s = s.substr(0, slen - 5);
				func("cbc");
			}
			else if (ss == "cbcbc") {
				s = s.substr(0, slen - 5);
				func("bcb");
			}
			else if (ss == "cacac") {
				s = s.substr(0, slen - 5);
				func("aca");
			}
			else if (ss == "acaca") {
				s = s.substr(0, slen - 5);
				func("cac");
			}
		}
	}
}

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

	cin >> T;
	while (T--) {
		cin >> S;
		s = "";

		func(S);

		if (s.length()) cout << "open\n";
		else cout << "closed\n";
	}
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 14170 // C++] Counting Haybales  (0) 2023.10.18
[BOJ 4138 // C++] Paper Route  (1) 2023.10.17
[BOJ 8310 // C++] Riddle  (0) 2023.10.15
[BOJ 18259 // C++] Greedy Pie Eaters  (0) 2023.10.14
[BOJ 18260 // C++] Bessie's Snow Cow  (0) 2023.10.13

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

 

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

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

 

8310번: Riddle

In the first line of the standard input there are three integers: n (1 ≤ n ≤ 1,000,000), denoting the number of towns in Voldebyte's riddle, m (0 ≤ m ≤ 1,000,000), denoting the number of roads, and k (1 ≤ k ≤ n), denoting the number of count

www.acmicpc.net

각 i번째 town이 capital이면 true, 그렇지 않으면 false 값을 갖는 bool 변수 \(T_i\)를 생각해보자. 만약 문제의 조건들을 2-CNF로 표현이 가능하다면 문제를 2-SAT문제로 모델링해 해결할 수 있을 것이다. 아래는 문제의 조건들을 2-CNF로 표현하는 과정이다.

 

우선 "각 간선의 적어도 한쪽 끝은 capital이어야 한다" 조건은 두 town의 번호가 \(x\)와 \(y\)일 때 \((T_x \lor T_y)\)로 표현할 수 있다.

 

"각 country에는 capital이 정확히 하나씩 있어야한다"는 조건은 "각 country에는 capital이 최대 하나 존재한다" 및 "각 country에는 capital이 최소 하나 존재한다"는 두 조건으로 나누어 생각할 수 있다. 한편, 후자 조건 없이 전자 제약만을 걸어 답을 얻은 다음 capital이 정해지지 않은 국가의 경우 아무 도시나 capital로 지정한다면 후자 조건이 같이 있는 경우의 답을 얻을 수 있고 이는 어렵지 않으므로 후자 조건 없이 전자 조건만을 이용한 해를 찾는 것으로 문제를 해결할 수 있게 된다.

 

이제 "각 country에는 capital이 최대 하나 존재한다" 조건을 CNF로 표현해보자. 어떤 country에 속한 town이 \(T_{c_1}...T_{c_w}\)라 하자. naive하게 2-CNF로 이 조건을 표현하는 한 가지 방법은 모든 \(1 \leq i,j \leq w (i \neq j)\)에 대하여 \((T_{c_i} \lor T_{c_j})\) 들의 논리곱으로 나타내는 것이다. 그러니 이러한 모든 식을 이용하기에는 그래프의 크기가 매우 커지므로 다른 방법을 생각해야한다.

 

새로운 bool 변수 \(S_i\)를 정의해 그 값을 \(i\) 이하의 모든 \(T_{c_i}\) 들을 or한 값과 동치인 값으로 정의하자. 이 때 \(T_{c_i} \implies S_i \), \(S_i \implies S_{i+1}\) 및 \(S_i \implies ~T_{c_{i+1}} \)와 같은 논리관계를 부여하면 \(O(w)\)개의 노드 및 간선만을 추가해 위의 조건을 확인할 수 있게 된다. (자주 쓰이는 테크닉이므로 알아두자.)

 

위의 각 논리식들은 2-CNF로 나타낼 수 있으므로 2-SAT을 해결하는 선형 알고리즘을 이용해 이 문제를 해결할 수 있다. 시간복잡도는 \(O(N + M)\)이다.

 

그래프의 크기 및 입출력의 양이 많아 같은 알고리즘이더라도 속도가 느린 언어 또는 비효율적인 구현으로는 통과하기 어려운 듯하다. 이는 그래프를 모델링할 때 각 country에 capital이 최소 하나 존재 존재한다는 조건을 제외하고 별도의 처리로 조건을 만족시킨 이유이기도 하다. 혹시 그래도 시간 초과가 날 경우 불필요한 구현이 없는지 확인해 문제를 해결하자.

 

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

#define NODE 4000001
#include <iostream>
#include <vector>
#include <string>
using namespace std;

int N, M, K; const int gap = 2000000; // 2-SAT 정점개수(TF분할 말고), T와F노드 사이 값의 차이
vector<int> G[NODE];
int dfi[NODE]; int dfidx = 1;
int sci[NODE]; int scidx = 1;
vector<int> stk;
int twosatdfs(int current) {
	stk.emplace_back(current);
	int ret = dfi[current] = dfidx++;
	for (auto node : G[current]) {
		if (sci[node]) continue;
		if (dfi[node]) ret = min(ret, dfi[node]);
		else ret = min(ret, twosatdfs(node));
	}

	if (ret == dfi[current]) {
		while (stk.back() != current) {
			sci[stk.back()] = scidx;
			stk.pop_back();
		}
		sci[stk.back()] = scidx++;
		stk.pop_back();
	}

	return ret;
}

bool ans[NODE];
bool TWOSAT() {
	for (int i = 1; i <= N; i++) {
		if (sci[i]) continue;
		twosatdfs(i);
	}
	for (int i = 1 + gap; i <= N + gap; i++) {
		if (sci[i]) continue;
		twosatdfs(i);
	}

	for (int i = 1; i <= N; i++) {
		if (sci[i] < sci[i + gap]) ans[i] = 1;
		else if (sci[i] > sci[i + gap]) ans[i] = 0;
		else return 0;
	}
	return 1;
}

int nxtid;
vector<int> towns[1000001];

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

	cin >> N >> M >> K;
	while (M--) {
		int x, y; cin >> x >> y;
		G[x + gap].emplace_back(y);
		G[y + gap].emplace_back(x);
	}

	nxtid = N;

	for (int k = 1; k <= K; k++) {
		int T; cin >> T;

		nxtid++;
		int old; cin >> old;
		G[old].emplace_back(nxtid);
		G[nxtid + gap].emplace_back(old + gap);

		towns[k].emplace_back(old);

		for (int t = 1; t < T; t++) {
			nxtid++;
			int x; cin >> x;
			G[x].emplace_back(nxtid);
			G[nxtid + gap].emplace_back(x + gap);
			G[nxtid - 1].emplace_back(nxtid);
			G[nxtid + gap].emplace_back(nxtid - 1 + gap);
			G[nxtid - 1].emplace_back(x + gap);
			G[x].emplace_back(nxtid - 1 + gap);
			
			towns[k].emplace_back(x);

			old = x;
		}
	}

	N = nxtid;

	if (TWOSAT()) {
		cout << "TAK\n";
		for (int k = 1; k <= K; k++) {
			bool has_capital = 0;
			for (auto t : towns[k]) {
				if (ans[t]) has_capital = 1, cout << t << ' ';
			}
			if (!has_capital) cout << towns[k].back() << ' ';
		}
	}
	else cout << "NIE";
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 4138 // C++] Paper Route  (1) 2023.10.17
[BOJ 4139 // C++] Octagons  (0) 2023.10.16
[BOJ 18259 // C++] Greedy Pie Eaters  (0) 2023.10.14
[BOJ 18260 // C++] Bessie's Snow Cow  (0) 2023.10.13
[BOJ 11999 // C++] Milk Pails (Bronze)  (1) 2023.10.12

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

 

이번에 볼 문제는 백준 18259번 문제인 Greedy Pie Eaters이다.
문제는 아래 링크를 확인하자.

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

 

18259번: Greedy Pie Eaters

Farmer John has $M$ cows, conveniently labeled $1 \ldots M$, who enjoy the occasional change of pace from eating grass. As a treat for the cows, Farmer John has baked $N$ pies ($1 \leq N \leq 300$), labeled $1 \ldots N$. Cow $i$ enjoys pies with labels in

www.acmicpc.net

\(dp[l][r]\)을 구간 \([l,r]\)에 포함된 파이만을 소들이 먹을 수 있을 때의 파이를 먹은 모든 소의 가중치의 합의 최댓값이라 정의하자. 이 때 문제에서 구하고자 하는 값은 \(dp[1][N]\)이 될 것이다. 

 

편의상 정확히 구간 \([l,r]\)의 파이를 먹어치우고자하는 소가 없는 경우 해당 구간에 \([l,r]\)의 파이를 먹어치우고자하는 가중치 0의 소가 존재한다고 생각하자. 이러한 가정을 하더라도 문제의 답에는 영향을 주지 않음을 확인하자.

 

구간 \([l,r]\)에 포함된 파이만을 소들이 (그 구간에서 가중치의 합이 최대가 되게끔) 파이를 먹는 과정에는 마지막으로 파이를 먹은 소가 항상 존재할 수밖에 없음을 관찰하자. 이로부터 "마지막으로 파이를 먹을 소가 파이를 먹기 전 상태"와 "마지막으로 파이를 먹을 소"에 대한 정보를 이용해 \(dp[l][r]\)의 값을 구할 점화식을 세워 문제를 해결할 것이다.

 

구체적으로 점화식을 세우는 방식을 서술하면 이렇다. "마지막으로 파이를 먹을 소"가 먹을 파이(중 하나)를 \(m\)이라 가정하자. 이 때, 이 소가 파이를 먹기 전까지는 \(m\) 위치에 있는 파이를 먹은 소가 존재할 수 없으므로 이 경우의 "마지막으로 파이를 먹을 소"가 파이를 먹기 전의 파이를 먹은 소들의 가중치의 합의 최댓값은 \(dp[l][m-1] + dp[m+1][r]\)이 된다. 이렇게 파이를 먹은 뒤 \(m\) 위치에 있는 파이를 먹을, 구간 \([l,r]\)에 포함되는 구간의 파이만을 먹을 최대 가중치 소를 고르면 "마지막으로 파이를 먹는 소가 \(m\) 위치의 파이를 먹을 경우"의 \(dp[l][r]\)의 최댓값을 구해낼 수 있다. 이를 \(l\) 이상 \(r\) 이하의 모든 \(m\)에 대하여 계산해 그중 최댓값을 구하면 \(dp[l][r]\)의 값을 계산할 수 있게 된다. 시간복잡도는 "\(m\) 위치에 있는 파이를 먹을, 구간 \([l,r]\)에 포함되는 구간의 파이만을 먹을 최대 가중치 소"의 가중치를 모두 알고 있다는 전제 하에 \(O(N^3)\)이 됨은 어렵지 않게 보일 수 있다.

 

이 과정에서 필요한 "\(m\) 위치에 있는 파이를 먹을, 구간 \([l,r]\)에 포함되는 구간의 파이만을 먹을 최대 가중치 소"의 가중치는 또다른 \(O(N^3)\) dp를 이용해 계산해낼 수 있다. 이는 어렵지 않으므로 설명을 생략한다.

 

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

#include <iostream>
using namespace std;

int N, M;
int seg[301][301];
int dp[301][301];
bool dpvisited[301][301];
int mx[301][301][301];
bool mxvisited[301][301][301];

int mxfunc(int l, int r, int m) {
	int& ret = mx[l][r][m];
	if (mxvisited[l][r][m]) return ret;
	mxvisited[l][r][m] = 1;

	ret = seg[l][r];
	if (l < m) ret = max(ret, mxfunc(l + 1, r, m));
	if (m < r) ret = max(ret, mxfunc(l, r - 1, m));
	
	return ret;
}

int dpfunc(int l, int r) {
	int& ret = dp[l][r];
	if (dpvisited[l][r]) return ret;
	dpvisited[l][r] = 1;

	if (l == r) return ret = seg[l][r];
	
	ret = max(ret, mxfunc(l, r, l) + dpfunc(l + 1, r));
	for (int k = l + 1; k < r; k++) {
		ret = max(ret, dpfunc(l, k - 1) + mxfunc(l, r, k) + dpfunc(k + 1, r));
	}
	ret = max(ret, dpfunc(l,r - 1) + mxfunc(l, r, r));

	return ret;
}

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

	cin >> N >> M;
	while (M--) {
		int w, l, r; cin >> w >> l >> r;
		seg[l][r] = w;
	}

	cout << dpfunc(1, N);
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 4139 // C++] Octagons  (0) 2023.10.16
[BOJ 8310 // C++] Riddle  (0) 2023.10.15
[BOJ 18260 // C++] Bessie's Snow Cow  (0) 2023.10.13
[BOJ 11999 // C++] Milk Pails (Bronze)  (1) 2023.10.12
[BOJ 18265 // C++] MooBuzz  (0) 2023.10.11

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

 

이번에 볼 문제는 백준 18260번 문제인 Bessie's Snow Cow이다.
문제는 아래 링크를 확인하자.

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

 

18260번: Bessie's Snow Cow

Snow has arrived on the farm, and as she does at the beginning of every winter, Bessie is building a snow-cow! Most of the time, Bessie strives to make her sculpture look as much like a real cow as possible. However, feeling artistically inspired, this yea

www.acmicpc.net

이 문제에서는 1번 노드를 루트로 갖는 트리에서 (1) x번 노드를 루트로 하는 서브트리에 색 c를 입히거나(단, 기존에 색을 가진 노드에 색을 칠해도 기존 색이 지워지지 않음) (2) x번 노드를 루트로 하는 서브트리에 속한 각 노드가 가지는 색의 개수의 합을 구하는 쿼리를 처리하는 문제이다.

 

이 문제에서는 서브트리에 대한 쿼리만을 처리할 것이므로 먼저 Euler Tour Technique을 이용해 주어진 트리를 배열로 펴 l구간합 lazy 세그먼트트리를 이용할 수 있게끔 인덱스를 새로 부여하는 전처리를 하자. 이 세그먼트트리는 각 노드 리프가 갖는 값이 그 노드가 갖는 색의 가짓수가 되게끔 관리할 것이고, 이렇게 관리된 세그먼트트리를 이용하면 (2)번 쿼리를 구간합 쿼리를 이용해 해결할 수 있음을 관찰할 수 있다. 이제 (1)번 쿼리를 처리하는 방법을 생각해보자.

 

만약 x번 노드를 루트로 하는 서브트리에 색이 c인 노드를 가진 노드가 전혀 없었다면 x번 노드를 루트로 갖는 서브트리의 노드들에 색의 종류를 전부 1씩 더하는 것으로 위의 목표를 달성할 수 있게 될 것이다. 그렇지 않은 경우는 다음과 같은 두 경우로 나누어 생각할 수 있다.

 

i) x번 노드에 c 색이 칠해져있지 않지만, 서브트리를 구성하는 노드 중 c로 이미 칠해진 노드가 있는 경우

이 경우 x번 노드의 서브트리에서 진행된 "c 칠하기" 시행을 "취소"한다면 위의 간단한 경우와 같이 쿼리를 처리할 수 있게 될 것이다. 이를 위해 기존에 입력으로 들어온 "노드 k에 c 칠하기" 시행들을 set 등을 이용해 관리하고 x번 노드의 서브트리에 속하는 모든 k에 대해 위에서 진행한 시행을 역으로 실행(k번 노드를 루트로 갖는 서브트리의 노드들에 색의 종류를 전부 -1씩 더하기)한 뒤 해당 set에서 그 노드들을 제거하는 등의 방법으로 이뤄낼 수 있다.

 

ii) x번 노드에 이미 c 색이 칠해져있는 경우

이 경우 다시 x번 노드에 c를 칠하려는 시도를 할 필요가 없다. 이 경우를 발견하기 위해 위에서 만든 "c 칠하기" 시행 set의 원소 중 x를 서브트리의 원소로 갖는 시행이 있었는지를 찾자. 위와 같이 관리된 set의 각 구간은 서로 겹치는 구간이 없고, set의 특성상 그러한 구간들이 오름차순으로 정렬되어있음을 이용하면 확인해야 할 노드는 많아야 1개이며 그 노드를 빠르게 찾아낼 수 있음을 관찰할 수 있다.

 

위의 관찰들을 이용해 문제를 해결하자.

 

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

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

int N, Q;
vector<int> G[100001];
int dfi[100001];
int childcnt[100001];
int dfsidx = 1;

int dfs(int cur) {
	int ret = 0;
	dfi[cur] = dfsidx++;
	for (auto& nxt : G[cur]) {
		if (dfi[nxt]) continue;
		ret += dfs(nxt);
	}

	childcnt[dfi[cur]] = ret;
	return ret + 1;
}

ll seg[262145];
ll lazy[262145];

void propagate(int L, int R, int sI) {
	seg[sI] += lazy[sI] * (R - L + 1);
	if (L < R) lazy[sI * 2] += lazy[sI], lazy[sI * 2 + 1] += lazy[sI];
	lazy[sI] = 0;
}

ll upd(int L, int R, int qL, int qR, ll qVal, int sI) {
	if (lazy[sI]) propagate(L, R, sI);
	if (qR < L || R < qL) return seg[sI];
	if (qL <= L && R <= qR) {
		lazy[sI] += qVal;
		propagate(L, R, sI);
		return seg[sI];
	}
	return seg[sI] = upd(L, (L + R) / 2, qL, qR, qVal, sI * 2) + upd((L + R) / 2 + 1, R, qL, qR, qVal, sI * 2 + 1);
}

ll qry(int L, int R, int qL, int qR, int sI) {
	if (lazy[sI]) propagate(L, R, sI);
	if (qR < L || R < qL) return 0;
	if (qL <= L && R <= qR) return seg[sI];
	return qry(L, (L + R) / 2, qL, qR, sI * 2) + qry((L + R) / 2 + 1, R, qL, qR, sI * 2 + 1);
}

set<int> st[100001];

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

	cin >> N >> Q;
	for (int i = 1; i < N; i++) {
		int x, y; cin >> x >> y;
		G[x].emplace_back(y);
		G[y].emplace_back(x);
	}

	dfs(1);

	while (Q--) {
		int q; cin >> q;
		if (q == 1) {
			int x, c; cin >> x >> c;
			x = dfi[x];

			if (!st[c].empty()) {
				auto iterT = st[c].lower_bound(x);
				if (iterT == st[c].begin()) {
					if (*iterT == x) continue;
				}
				else {
					iterT = prev(iterT);
					int tmp = *iterT;
					if (tmp <= x && x <= tmp + childcnt[tmp]) continue;
				}
			}

			auto iterL = st[c].lower_bound(x), iterR = st[c].upper_bound(x + childcnt[x]);
			auto iter = iterL;
			while (iter != iterR) {
				int cur = *iter;
				upd(1, N, cur, cur + childcnt[cur], -1, 1);
				iter++;
			}
			st[c].erase(iterL, iterR);
			st[c].insert(x);
			upd(1, N, x, x + childcnt[x], 1, 1);
		}
		else {
			int x; cin >> x;
			x = dfi[x];
			cout << qry(1, N, x, x + childcnt[x], 1) << '\n';
		}
	}
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 8310 // C++] Riddle  (0) 2023.10.15
[BOJ 18259 // C++] Greedy Pie Eaters  (0) 2023.10.14
[BOJ 11999 // C++] Milk Pails (Bronze)  (1) 2023.10.12
[BOJ 18265 // C++] MooBuzz  (0) 2023.10.11
[BOJ 18266 // C++] Meetings  (0) 2023.10.10

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

 

이번에 볼 문제는 백준 11999번 문제인 Milk Pails (Bronze)이다.
문제는 아래 링크를 확인하자.

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

 

11999번: Milk Pails (Bronze)

Farmer John has received an order for exactly \(M\) units of milk (\(1 \leq M \leq 1,000\)) that he needs to fill right away. Unfortunately, his fancy milking machine has just become broken, and all he has are three milk pails of integer sizes \(X\), \(Y\)

www.acmicpc.net

양의 정수 K에 대하여 정확히 K만큼의 우유를 통에 채울 수 있다면 마지막으로 우유를 붓기 전에는 정확히 K-X 또는 K-Y만큼의 우유가 통에 채워져있었어야 함을 관찰하자.

 

위의 관찰을 이용하면, 0부터 모든 음이 아닌 정수를 차례로 보면서 현재 정수만큼의 우유를 정확히 채울 수 있다면 K+X, K+Y의 우유 또한 정확히 채울 수 있음을 기록해나가 문제를 해결할 수 있음을 알 수 있다.

 

위의 내용을 구현해 문제를 해결하자. 이 때, K+X 및 K+Y의 값은 M을 넘을 수 있음에 유의해 구현하자.

 

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

#include <iostream>
using namespace std;

int X, Y, M;
bool visited[2001];

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

	visited[0] = 1;
	cin >> X >> Y >> M;

	for (int i = 0; i < M; i++) {
		if (visited[i]) visited[i + X] = visited[i + Y] = 1;
	}

	for (int i = M; i > -1; i--) {
		if (visited[i]) {
			cout << i;
			break;
		}
	}
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 18259 // C++] Greedy Pie Eaters  (0) 2023.10.14
[BOJ 18260 // C++] Bessie's Snow Cow  (0) 2023.10.13
[BOJ 18265 // C++] MooBuzz  (0) 2023.10.11
[BOJ 18266 // C++] Meetings  (0) 2023.10.10
[BOJ 18267 // C++] Milk Visits  (0) 2023.10.09

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

 

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

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

 

18265번: MooBuzz

Farmer John's cows have recently become fans of playing a simple number game called "FizzBuzz". The rules of the game are simple: standing in a circle, the cows sequentially count upward from one, each cow saying a single number when it is her turn. If a c

www.acmicpc.net

3의 배수 또는 5의 배수에는 Moo를, 그 외의 수는 해당 수를 외칠 때 N번째로 외치게 되는 수가 무엇인지를 구하는 문제이다.

 

어떤 수가 3의 배수 또는 5의 배수인지 아닌지의 여부는 3과 5의 최소공배수인 15를 주기로 일정한 규칙을 갖고 반복되는 점을 이용해 문제를 해결하자. 증명은 간단한 정수론이므로 생략한다.

 

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

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

ll N;
ll arr[8] = { 1,2,4,7,8,11,13,14 };

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

	cin >> N;
	N--;
	cout << (N / 8) * 15 + arr[N % 8];
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 18260 // C++] Bessie's Snow Cow  (0) 2023.10.13
[BOJ 11999 // C++] Milk Pails (Bronze)  (1) 2023.10.12
[BOJ 18266 // C++] Meetings  (0) 2023.10.10
[BOJ 18267 // C++] Milk Visits  (0) 2023.10.09
[BOJ 3188 // C++] nule  (0) 2023.10.08

+ Recent posts