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

 

이번에 볼 문제는 백준 18131번 문제인 치삼이의 플레이리스트이다.
문제는 아래 링크를 확인하자.

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

 

18131번: 치삼이의 플레이리스트

첫 번째 줄에 세 개의 정수로 현재 플레이리스트 곡 수 N(1 ≤ N ≤ 1,000)과 주어지는 명령의 개수 M(1 ≤ M ≤ 10,000), 곡이 삭제되는 기준 S(1 ≤ S ≤ 100,000,000)가 주어진다. 두 번째 줄부터 N+1

www.acmicpc.net

문제에 주어진 "플레이리스트"의 작동을 그대로 구현하는 문제이다.

 

모든 명령을 벡터의 erase와 insert를 이용해 구현해도 충분히 시간 내에 돌 수 있을 정도로 입력크기가 제한되어 있으므로 벡터를 이용해 단순하게 지문에 적힌대로 구현해주자.

 

다음으로 곡을 재생할 때 어떤 곡의 몇 초부터 재생해야하는가에 대한 정보가 필요하므로 이를 기록해두는 전역변수를 선언하면 구현을 편하게 해낼 수 있을 것이다.

 

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

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

int N, M, S;
int playid, playmin;
vector<pair<pair<string, int>, int>> playlist; // {{제목,곡길이},치삼지수}

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

	cin >> N >> M >> S;
	for (int n = 0; n < N; n++) {
		string s; int mn; cin >> s >> mn;
		playlist.emplace_back(make_pair(make_pair(s, mn), 0));
	}
	while (M--) {
		string q; cin >> q;
		if (q == "L") {
			int T; cin >> T;
			while (T && playid < N) {
				if (T >= playlist[playid].first.second - playmin) {
					playlist[playid].second += (playlist[playid].first.second - playmin) * (playid + 1);
					T -= playlist[playid].first.second - playmin;
					if (playlist[playid].second >= S) {
						cout << playlist[playid].first.first << '\n';
						playlist.erase(playlist.begin() + playid);
						playmin = 0;
						N--;
					}
					else playid++, playmin = 0;
				}
				else {
					playlist[playid].second += T * (playid + 1);
					playmin += T;
					T = 0;
					if (playlist[playid].second >= S) {
						cout << playlist[playid].first.first << '\n';
						playlist.erase(playlist.begin() + playid);
						playmin = 0;
						N--;
					}
				}
			}
		}
		else if (q == "AR") {
			int id = -1, mx = -1;
			for (int i = 0; i < N; i++) {
				auto& p = playlist[i];
				if (p.second > mx) id = i, mx = p.second;
			}
			if (id < 0) cout << -1 << '\n';
			else {
				cout << playlist[id].first.first << '\n';
				if (playid > id) playid--;
				else if (playid == id) playmin = 0;
				playlist.erase(playlist.begin() + id);
				N--;
			}
		}
		else if (q == "R") {
			string s; cin >> s;
			int id = -1;
			for (int i = 0; i < N; i++) {
				auto& p = playlist[i];
				if (p.first.first == s) id = i;
			}
			if (id < 0) cout << -1 << '\n';
			else {
				cout << playlist[id].second << '\n';
				if (playid > id) playid--;
				else if (playid == id) playmin = 0;
				playlist.erase(playlist.begin() + id);
				N--;
			}
		}
		else if (q == "P") {
			string s; int mn; cin >> s >> mn;
			playlist.insert(playlist.begin(), make_pair(make_pair(s, mn), 0));
			playid = 0, playmin = 0;
			N++;
		}
		else if (q == "AE") {
			int mx = -1;
			for (auto& p : playlist) {
				mx = max(mx, p.second);
			}

			cout << mx << '\n';
		}
		else {
			int ret = -1;
			string s; cin >> s;
			for (auto& p : playlist) {
				if (p.first.first == s) {
					ret = p.second;
					break;
				}
			}

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

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

 

이번에 볼 문제는 백준 18133번 문제인 가톨릭대학교에 워터 슬라이드를??이다.
문제는 아래 링크를 확인하자.

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

 

18133번: 가톨릭대학교에 워터 슬라이드를??

두 정수 N (2 ≤ N ≤ 100,000), M (1 ≤ M ≤ 100,000)이 주어진다. N 은 건물의 개수를, M 은 터널의 개수를 나타낸다. 건물 옥상들의 번호는 1과 N 사이의 정수다. 다음 M개의 줄에는 각각 두 정

www.acmicpc.net

주어진 문제의 상황을 건물을 노드로, 터널을 방향이 있는 에지로 보아 그래프로 모델링하자.

 

같은 SCC 내에 속한 노드들은 서로 방문했다가 다시 자기 자신으로 돌아올 수 있다는 성질이 있음을 상기하자. 이를 이용해 주어진 그래프의 각 SCC를 노드로 하는 condensation graph의 indegree가 0인 노드의 개수를 세는 것으로 문제를 해결할 수 있다.

 

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

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

int N, M;
vector<int> G[100001];
int dfi[100001];
int dfidx = 1;
int ndi[100001];
int ndidx = 1;

vector<int> stk;

int dfs(int cur) {
	stk.emplace_back(cur);
	int ret = dfi[cur] = dfidx++;
	for (auto& x : G[cur]) {
		if (dfi[x]) {
			if (!ndi[x]) ret = min(ret, dfi[x]);
		}
		else ret = min(ret, dfs(x));
	}

	if (dfi[cur] == ret) {
		while (stk.back() != cur) {
			ndi[stk.back()] = ndidx;
			stk.pop_back();
		}
		ndi[stk.back()] = ndidx++;
		stk.pop_back();
	}

	return ret;
}

int indegree[100001];
int ans;

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

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

	for (int n = 1; n <= N; n++) {
		if (!ndi[n]) dfs(n);
	}

	for (int cur = 1; cur <= N; cur++) {
		for (auto& nxt : G[cur]) {
			if (ndi[cur] != ndi[nxt]) indegree[ndi[nxt]]++;
		}
	}

	for (int i = 1; i < ndidx; i++) {
		if (!indegree[i]) ans++;
	}

	cout << ans;
}
728x90

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

 

이번에 볼 문제는 백준 18132번 문제인 내 이진트리를 돌려줘!!!이다.
문제는 아래 링크를 확인하자.

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

 

18132번: 내 이진트리를 돌려줘!!!

각 테스트 케이스에 대해 이진 트리의 경우의 수를 1,000,000,007로 나눈 나머지를 출력하시오.

www.acmicpc.net

에지가 하나 이상 있는 트리는 (1)루트에 자식이 하나 있거나 (2) 루트에 자식이 두개 있는 두가지 경우중 정확히 하나를 만족함을 관찰하자.

 

위의 관찰을 이용하면 루트의 자식 하나 또는 둘을 루트로 갖는 서브트리의 경우의 수를 이용해 점화식을 세워 문제를 해결할 수 있다.

 

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

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

int T;
ll dp[5001];

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

	dp[0] = 1, dp[1] = 2;
	for (ll n = 2; n < 5001; n++) {
		dp[n] = dp[n - 1] * 2;
		for (ll m = 0; m < n - 1; m++) {
			dp[n] = (dp[n] + dp[m] * dp[n - m - 2]) % MOD;
		}
	}

	cin >> T;
	while (T--) {
		int E; cin >> E;
		cout << dp[E] << '\n';
	}
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 2435 // C++] 기상청 인턴 신현수  (0) 2023.08.14
[BOJ 4593 // C++] Rock, Paper, Scissors  (0) 2023.08.14
[BOJ 18135 // C++] 겨울나기  (0) 2023.08.12
[BOJ 18134 // C++] 치삼이의 대모험  (0) 2023.08.11
[BOJ 1925 // C++] 삼각형  (0) 2023.08.10

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

 

이번에 볼 문제는 백준 18135번 문제인 겨울나기이다.
문제는 아래 링크를 확인하자.

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

 

18135번: 겨울나기

다다의 작업입력 중 첫 번째 정수가 1인 경우 이어 입력받은 x부터 y칸에 해당하는 영역에 저장된 도토리 개수의 합을 출력한다. 모든 값의 범위는 263보다 작다.

www.acmicpc.net

주어지는 각 칸과 영역에 대하여 각 칸이 어느 영역에 포함되어있는지를 나타내는 배열을 하나 만들자. 그러면 주어진 문제는 영역들의 관점에서 보아, 일차원 배열 위에서의 구간 업데이트와 구간 합 쿼리를 지원하는 자료구조를 이용해 해결할 수 있게 변형됨을 쉽게 관찰할 수 있다.

 

lazy propagation을 지원하는 구간 합 segment tree를 이용해 문제를 해결해주자.

 

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

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

int N, M;
int id[2000001];
ll arr[1000001];
ll seg[2097153];
ll lazy[2097153];

void prop(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 init(int L, int R, int sI) {
	if (L < R) return seg[sI] = init(L, (L + R) / 2, sI * 2) + init((L + R) / 2 + 1, R, sI * 2 + 1);
	else return seg[sI] = arr[L];
}

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

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

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

	cin >> N >> M;
	for (int m = 1; m <= M; m++) {
		int a, b; ll c; cin >> a >> b >> c;
		arr[m] = c;
		if (a <= b) {
			for (int i = a; i <= b; i++) id[i] = m;
		}
		else {
			for (int i = a; i <= N; i++) id[i] = m;
			for (int i = 1; i <= b; i++) id[i] = m;
		}
	}

	init(1, M, 1);

	int q, x, y, z;
	cin >> q;
	while (q) {
		if (q == 1) {
			cin >> x >> y;
			x = id[x], y = id[y];
			if (x <= y) cout << rsum(1, M, x, y, 1) << '\n';
			else cout << rsum(1, M, x, M, 1) + rsum(1, M, 1, y, 1) << '\n';
		}
		else {
			cin >> x >> y >> z;
			x = id[x], y = id[y];
			if (x <= y) rupd(1, M, x, y, z, 1);
			else {
				rupd(1, M, x, M, z, 1), rupd(1, M, 1, y, z, 1);
			}
		}
		cin >> q;
	}
}
728x90

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

 

이번에 볼 문제는 백준 18134번 문제인 치삼이의 대모험이다.
문제는 아래 링크를 확인하자.

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

 

18134번: 치삼이의 대모험

첫 번째 줄에 골목길의 교차점 개수 N(3 ≤ N ≤ 1,000)과 골목길의 개수 M(3 ≤ M ≤ 10,000)이 주어진다. 두 번째 줄부터 M개의 줄에 골목길의 정보가 주어진다. 각 줄에는 3개의 정수로 골목길의

www.acmicpc.net

주어진 문제의 답이 되는 경로를 찾는 것은 H에서 T로 가는, vertex-disjoint하고 가중치의 총합이 최소인 두 경로의 그 가중치의 총합을 구하는 문제로 생각할 수 있다.

 

이는 주어진 그래프에서 각 에지와 꼭짓점(H와 T 제외)에 허용된 유량을 1, 각 에지의 비용을 L이라 할 때 H에서 T로 2의 유량을 최소비용으로 흘리는 문제로 생각할 수 있다. MCMF 문제를 해결하는 알고리즘을 이용해 문제를 해결해주자.

 

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

#define NODE 2002
#define INF 1000000007
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;

int source = 0, sink = 2001;
int edge[NODE][NODE], cost[NODE][NODE];
vector<int> G[NODE];

int par[NODE];
int stepcost[NODE];
int inque[NODE];

pair<int, int> MCMF() { // {maxflow, mincost}
    int retflow = 0, retcost = 0;
    while (1) {
        memset(par, -1, sizeof(par));
        memset(inque, 0, sizeof(inque));
        fill(stepcost, stepcost + NODE, INF);
        stepcost[source] = 0;

        queue<int> que;
        que.push(source);
        inque[source] = 1;

        while (!que.empty()) {
            int cur = que.front(); que.pop();
            inque[cur] = 0;
            for (auto& nxt : G[cur]) {
                if (edge[cur][nxt] > 0 && stepcost[cur] + cost[cur][nxt] < stepcost[nxt]) {
                    stepcost[nxt] = stepcost[cur] + cost[cur][nxt];
                    par[nxt] = cur;
                    if (!inque[nxt]) {
                        que.push(nxt);
                        inque[nxt] = 1;
                    }
                }
            }
        }

        if (par[sink] == -1) break;

        int flow = INF;
        for (int i = sink; i != source; i = par[i]) flow = min(flow, edge[par[i]][i]);
        for (int i = sink; i != source; i = par[i]) {
            retcost += cost[par[i]][i] * flow;
            edge[par[i]][i] -= flow;
            edge[i][par[i]] += flow;
        }
        retflow += flow;
    }

    return make_pair(retflow, retcost);
}

int N, M, H, T;

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

    cin >> N >> M;
    for (int n = 1; n <= N; n++) {
        G[n].emplace_back(n + 1000);
        G[n + 1000].emplace_back(n);
        edge[n][n + 1000] = 1;
    }
    while (M--) {
        int L, U, V; cin >> L >> U >> V;
        G[U + 1000].emplace_back(V);
        G[V].emplace_back(U + 1000);
        G[V + 1000].emplace_back(U);
        G[U].emplace_back(V + 1000);
        edge[U + 1000][V] = edge[V + 1000][U] = 1;
        cost[U + 1000][V] = cost[V + 1000][U] = L, cost[U][V + 1000] = cost[V][U + 1000] = -L;
    }
    cin >> H >> T;
    G[source].emplace_back(H + 1000);
    G[T].emplace_back(sink);
    edge[source][H + 1000] = edge[T][sink] = 2;

    auto p = MCMF();
    if (p.first < 2) cout << -1;
    else cout << p.second;
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 18132 // C++] 내 이진트리를 돌려줘!!!  (0) 2023.08.13
[BOJ 18135 // C++] 겨울나기  (0) 2023.08.12
[BOJ 1925 // C++] 삼각형  (0) 2023.08.10
[BOJ 1972 // C++] 놀라운 문자열  (0) 2023.08.09
[BOJ 1996 // C++] 지뢰 찾기  (0) 2023.08.08

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

 

이번에 볼 문제는 백준 18130번 문제인 여름나기이다.
문제는 아래 링크를 확인하자.

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

 

18130번: 여름나기

첫 줄에 두 정수 진열된 손 선풍기의 개수 N(1 ≤ N ≤ 10,000) 와 현석이가 집까지 가는데 걸어가는 시간 Q(1 ≤ Q ≤ 1,000,000)가 주어진다. 두 번째 줄부터 N+1번째 줄까지 세 정수 P, K, C가 주어지는데

www.acmicpc.net

각 손 선풍기를 이용할 때 지불하게 될 총액을 계산하는 식을 하나 만들고, 반복문을 이용해 가장 비용이 적게 드는 손 선풍기를 찾아 그 번호와 그 때의 비용을 출력하는 것으로 문제를 해결하자.

 

추가비용을 낼 시점의 수를 나눗셈의 몫을 이용하여 먼저 계산한다면 총 추가비용을 구하는 식을 어렵지 않게 유도할 수 있을 것이다.

 

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

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

int N, Q;
ll id;
ll ans = 9223372036854775807LL;

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

	cin >> N >> Q;
	for (int n = 1; n <= N; n++) {
		ll P, K, C; cin >> P >> K >> C;
		ll cnt = (Q - 1) / K;

		ll val = P + cnt * (cnt + 1) / 2 * C;
		if (val < ans) id = n, ans = val;
	}

	cout << id << ' ' << ans;
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 6600 // C++] 원의 둘레  (0) 2023.01.10
[BOJ 25558 // C++] 내비게이션  (0) 2023.01.10
[BOJ 27110 // C++] 특식 배부  (0) 2023.01.10
[BOJ 26949 // C++] Kylskåpstransport  (0) 2023.01.10
[BOJ 18126 // C++] 너구리 구구  (0) 2023.01.09

+ Recent posts