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

 

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

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

 

\(i\)번째 꽃까지 보았을 때 마야가 현재 도달할 수 있는 높이의 범위가 \(L\) 이상 \(R\) 이하라고 가정해보자. 이 때 높이가 \(H\)인 \(i+1\)번째 꽃을 보았을 때 해당 꽃에 도달이 가능하다면 \(L\)과 \(R\)은 각각 \(\min(L,H-K)\)와 \(\max(R,H+K)\)가 될 것이고, 그렇지 않다면 \(L\)과 \(R\)은 그대로 유지될 것이다.

 

초기상태(첫 꽃에 마야가 있는 상태)에서 도달할 수 있는 위치의 범위는 하나의 닫힌 구간으로 나타낼 수 있고 과정을 반복해도 상태는 닫힌 구간으로 나타나므로, 위의 과정을 통해 각 꽃에 마야가 도달할 수 있는지를 항상 판정할 수 있다.

 

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

#include <iostream>
using namespace std;

int N, K, L, R;

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

	cin >> N >> K >> L;
	R = L;
	L -= K, R += K;
	cout << 1;
	for (int i = 1; i < N; i++) {
		int x; cin >> x;
		if (x < L || R < x) cout << ' ' << 0;
		else {
			cout << ' ' << 1;
			L = min(L, x - K), R = max(R, x + K);
		}
	}
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 32589 // C++] Flag Rotation  (2) 2024.10.31
[BOJ 32585 // C++] Building Pyramids  (2) 2024.10.30
[BOJ 20104 // C++] Timecard  (1) 2024.10.28
[BOJ 2014 // C++] 소수의 곱  (1) 2024.10.25
[BOJ 16021 // C++] Choose your own path  (2) 2024.10.24

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

 

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

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

 

읽을 \(N\)개의 문자열의 개수를 인수로 넘겨주는 초기화 함수와 각 문자열을 구성하는 문자 중 알파벳 대문자를 소문자로 바꿔 리턴하는 함수를 작성하는 문제이다.

 

어차피 대소문자 변환 함수는 채점기가 알아서 \(N\)번 호출하므로 전자는 아무런 행동도 하지 않아도 됨을 확인하자.

 

주어지는 알파벳 문자 중 대문자를 소문자로 바꾸는 것은 tolower 함수를 이용해 간단히 해낼 수 있다.

 

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

#include "timecard.h"
#include <string>
using namespace std;

void init(int n) {

}

string convert(string s) {
	for (auto &l:s) l = tolower(l);
	return s;
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 32585 // C++] Building Pyramids  (2) 2024.10.30
[BOJ 32533 // C++] Skokovi  (1) 2024.10.29
[BOJ 2014 // C++] 소수의 곱  (1) 2024.10.25
[BOJ 16021 // C++] Choose your own path  (2) 2024.10.24
[BOJ 32383 // C++] 점프  (2) 2024.10.23

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

 

이번에 볼 문제는 백준 2014번 문제인 소수의 곱이다.
문제는 아래 링크를 확인하자.

 

어떤 양의 정수 \(k\)에 대하여 \(k\)가 증가할 때 주어진 소수들의  곱으로 표현할 수 있는 \(k\) 이하의 양의 정수의 개수는 증가하거나 그대로 유지된다. 따라서, 그 개수를 빠르게 구할 수 있다면 이분탐색으로 문제의 답을 구할 수 있음을 관찰하자. 이제 이 개수를 빠르게 계산할 수 있는 방법을 생각해보자.

 

가능한 한 가지 방법으로 DP가 있다. 구체적으로, 모든 양의 정수는 가장 큰 소인수가 존재함을 이용해 상태를 정의하고, 이를 이용해 dp로 문제를 해결할 수 있다.

 

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

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

ll N, K;
ll P[100];
ll L = 1, R = 2147483647;

map<pair<ll, int>, ll> dp;

ll func(ll X, ll idx) {
	if (idx == N || X < P[idx]) return 1;
	if (dp.count(make_pair(X, idx))) return dp[make_pair(X, idx)];
	ll val = 0;
	for (ll x = 1; x <= X; x *= P[idx]) {
		val += func(X / x, idx + 1);
		if (val > K) {
			val = K + 1;
			break;
		}
	}
	return dp[make_pair(X, idx)] = val;
}

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

	cin >> N >> K;
	for (int i = 0; i < N; i++) cin >> P[i];
	while (L < R) {
		ll mid = (L + R) / 2;
		if (func(mid, 0) - 1 < K) L = mid + 1;
		else R = mid;
	}
	cout << L;
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 32533 // C++] Skokovi  (1) 2024.10.29
[BOJ 20104 // C++] Timecard  (1) 2024.10.28
[BOJ 16021 // C++] Choose your own path  (2) 2024.10.24
[BOJ 32383 // C++] 점프  (2) 2024.10.23
[BOJ 6248 // C++] Bronze Cow Party  (1) 2024.10.22

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

 

이번에 볼 문제는 백준 16021번 문제인 Choose your own path이다.
문제는 아래 링크를 확인하자.

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

 

각 책 페이지를 정점으로, 한 페이지에서 다른 페이지로 이동할 수 있는 관계를 에지로 하는 그래프로 문제를 모델링하자. 이 때, 구성한 그래프에서 첫 페이지를 나타내는 정점에서 출발해 도달할 수 있는 모든 다른 정점까지의 최단거리는 bfs를 통해 간단히 구할 수 있다.

 

모든 정점이 도달할 수 있는 정점인지, 그리고 도달할 수 있는 모든 엔딩 페이지에 대하여 첫 페이지와 가장 가까운 정점(항상 존재함을 문제의 조건이 보장한다.)의 거리를 bfs의 결과를 통해 구하고 문제를 해결하자.

 

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

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

int N, K;
vector<int> E, G[10001];
int dist[10001];
queue<int> que;
int mn = 1000000007;
bool chk = 1;

void bfs() {
	dist[1] = 1;
	que.push(1);
	while (!que.empty()) {
		int cur = que.front(); que.pop();
		for (auto &nxt:G[cur]) {
			if (!dist[nxt]) que.push(nxt), dist[nxt] = dist[cur] + 1;
		}
	}
}

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

	cin >> N;
	for (int i = 1; i <= N; i++) {
		cin >> K;
		if (!K) E.emplace_back(i);
		else {
			while (K--) {
				int x; cin >> x;
				G[i].emplace_back(x);
			}
		}
	}

	bfs();
	for (int i = 1; i <= N; i++) {
		if (!dist[i]) chk = 0;
	}
	if (chk) cout << "Y\n";
	else cout << "N\n";
	for (auto &x:E) {
		if (!dist[x]) continue;
		mn = min(mn, dist[x]);
	}

	cout << mn;
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 20104 // C++] Timecard  (1) 2024.10.28
[BOJ 2014 // C++] 소수의 곱  (1) 2024.10.25
[BOJ 32383 // C++] 점프  (2) 2024.10.23
[BOJ 6248 // C++] Bronze Cow Party  (1) 2024.10.22
[BOJ 5526 // C++] ダーツ (Darts)  (2) 2024.10.21

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

 

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

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

 

가장 낮은 건물 에서 다른 건물로 이동할 때 다음 이동이 어떻게 되어야 하는지 생각해보자. 모든 건물의 높이는 서로 다르다는 조건에 의해 이는 항상 존재한다.

 

이 건물이 맨 왼쪽 또는 오른쪽에 있다면 다음 이동은 항상 유일하게 인접한 건물이 될 것이다. 그보다 더 높은 높이의 건물이 이후에 나오더라도 해당 건물을 경유해 이동하는 것이 항상 체력상 이득이기 때문이다.

 

이 건물이 맨 왼쪽 또는 오른쪽이 아니라면 왼쪽 건물과 오른쪽 건물이 모두 존재할 것이다. 이 중 더 높은 건물로 향하는 경우 한번에 그 건물로 이동하는 것보다 더 낮은 건물을 경유해서 이동하는 것이 항상 이득임을 알 수 있다. 또한 그 외의 건물로의 이동은 앞서 본 것과 같은 이유로 항상 손해임을 알 수 있다.

 

한편, 어떤 두 건물 사이의 직접 이동이 가능한 경우 이동 과정에서 굳이 두 건물 모두보다 낮은 건물로 이동했다가 다시 이동하는 작업은 필요없음을 관찰하자. 따라서 위에서 구한 이동을 제외하면 가장 낮은 건물을 경유하는 이동은 더 존재하지 않음을 알 수 있다.

 

이러한 관찰을 적절히 일반화하면, 모든 이동은 (가장 높은 건물을 제외한) 각 건물의 가장 가까운 왼쪽 및 오른쪽 높은 건물(단, 해당 방향에 존재하는 경우에 한정한다.)로의 이동의 형태만으로 이루어져야 함을 알 수 있다. 이러한 이동을 모으면 트리가 되고, 이 트리 위에서의 모든 경로(가중치는 각 이동의 체력 소모량과 같고, 방향만 다른 것은 같은 경로로 친다)의 가중치의 합을 계산하는 것으로 문제를 해결할 수 있게 된다.

 

이 문제의 해결 과정에서 구성한 것과 같은 트리를 Cartesian Tree(데카르트 트리)라 부른다. Cartesian Tree는 선형 시간에도 구성할 수 있음이 잘 알려져 있으니 관심이 있다면 찾아보자.

 

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

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

int N;
int A[500002][2];
int L[500002], R[500002];
int findL(int x) {
	if (x == L[x]) return x;
	return L[x] = findL(L[x]);
}
int findR(int x) {
	if (x == R[x]) return x;
	return R[x] = findR(R[x]);
}
ll ans;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;

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

	cin >> N;
	for (int i = 1; i <= N; i++) L[i] = i, R[i] = i;
	for (int i = 1; i <= N; i++) {
		cin >> A[i][0], A[i][1] = 1;
		pq.push(make_pair(A[i][0], i));
	}

	while (!pq.empty()) {
		int cur = pq.top().second; pq.pop();
		L[cur] = cur - 1, R[cur] = cur + 1;
		int l = findL(cur), r = findR(cur);
		if (!l && !r) continue;
		if (!l) {
			ll g = A[r][0] - A[cur][0];
			ans += g * g % 1000000007 * A[cur][1] % 1000000007 * (N - A[cur][1]) % 1000000007;
			A[r][1] += A[cur][1];
		}
		else if (!r) {
			ll g = A[l][0] - A[cur][0];
			ans += g * g % 1000000007 * A[cur][1] % 1000000007 * (N - A[cur][1]) % 1000000007;
			A[l][1] += A[cur][1];
		}
		else if (A[l][0] < A[r][0]) {
			ll g = A[l][0] - A[cur][0];
			ans += g * g % 1000000007 * A[cur][1] % 1000000007 * (N - A[cur][1]) % 1000000007;
			A[l][1] += A[cur][1];
		}
		else {
			ll g = A[r][0] - A[cur][0];
			ans += g * g % 1000000007 * A[cur][1] % 1000000007 * (N - A[cur][1]) % 1000000007;
			A[r][1] += A[cur][1];
		}
	}
	cout << ans % 1000000007;
}

 

728x90

'BOJ' 카테고리의 다른 글

[BOJ 2014 // C++] 소수의 곱  (1) 2024.10.25
[BOJ 16021 // C++] Choose your own path  (2) 2024.10.24
[BOJ 6248 // C++] Bronze Cow Party  (1) 2024.10.22
[BOJ 5526 // C++] ダーツ (Darts)  (2) 2024.10.21
[BOJ 1229 // C++] 육각수  (1) 2024.10.18

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

 

이번에 볼 문제는 백준 6248번 문제인 Bronze Cow Party이다.
문제는 아래 링크를 확인하자.

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

 

\(X\)에서 어떤 지점까지 이동하는 데에 드는 최소 시간을 구할 수 있다면 그 지점까지 갔다가 돌아오는 데에 드는 최소시간은 그 두 배임을 알 수 있다.

 

따라서 각 지점까지 이동하는 데에 드는 최소 시간을 각각 구하고, 그 중 가장 큰 값을 찾아 문제의 답을 계산할 수 있다.

 

음이 아닌 가중치를 갖는 그래프에서의 한 꼭짓점에서 다른 모든 꼭짓점까지의 최단거리는 다익스트라 알고리즘을 이용해 간단히 구할 수 있다.

 

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

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

int N, M, S;
vector<pair<int, int>> G[1001];
int dist[1001];
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;
int mx;

void dijkstra() {
	memset(dist, 0x3f, sizeof(dist));
	dist[S] = 0;
	pq.push(make_pair(0, S));
	while (!pq.empty()) {
		int cur = pq.top().second, d = pq.top().first; pq.pop();
		if (dist[cur] < d) continue;
		mx = dist[cur];
		for (auto &p : G[cur]) {
			int nxt = p.first, dd = p.second + d;
			if (dist[nxt] > dd) dist[nxt] = dd, pq.push(make_pair(dd, nxt));
		}
	}
}

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

	cin >> N >> M >> S;
	while (M--) {
		int x, y, w; cin >> x >> y >> w;
		G[x].emplace_back(make_pair(y, w));
		G[y].emplace_back(make_pair(x, w));
	}

	dijkstra();
	cout << mx * 2;
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 16021 // C++] Choose your own path  (2) 2024.10.24
[BOJ 32383 // C++] 점프  (2) 2024.10.23
[BOJ 5526 // C++] ダーツ (Darts)  (2) 2024.10.21
[BOJ 1229 // C++] 육각수  (1) 2024.10.18
[BOJ 1341 // C++] 사이좋은 형제  (2) 2024.10.17

+ Recent posts