2021.01.03. 15:00 virtual 참가 / performance = 1563
[풀이]
1153A. Serval and Bus (*1000)
버스별로 정류장에 처음 도착하는 시간과 배차간격이 주어질 때, 버스정류장에 t초에 도착했을 때 제일 먼저 탈 수 있는 버스를 구하는 문제이다.
처음에 A번치고 생각보다 까다로웠으나, n이 100이고 t가 10만이기 때문에 각 버스별로 정류장에 도착하는 시간을 모두 구해줘도 무방하다.
나는 priority_queue를 이용하여 현재 pq에 담겨있는 버스들의 도착 시간 중에 제일 빠른 것을 확인해서,
t보다 작다면 배차간격만큼 더해줘서 다시 넣어주고, 처음으로 t보다 큰 값이 나온 경우에 출력을 해주었다.
#include<bits/stdc++.h>
using namespace std;
using pii = pair<int, int>;
int main(void) {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int n, t; cin >> n >> t;
priority_queue<pair<pii, int>> pq;
for (int i = 1; i <= n; i++) {
int s, d; cin >> s >> d;
pq.push({ { -s, d }, i });
}
while (1) {
int now = -pq.top().first.first;
int plus = pq.top().first.second;
int ans = pq.top().second;
pq.pop();
if (now >= t) {
cout << ans;
break;
}
else {
pq.push({ {-(now + plus), plus}, ans });
}
}
}
1153B. Serval and Toy Bricks (*1200)
옆면과 앞면, 윗면에서 본 입체 도형이 주어질 때, 실제로 가능한 입체 도형을 구하는 문제이다.
옆면과 앞면에서 각각 봤을 때 각 열 별로 최대 높이인 블록의 높이가 저장되므로,
ans[i][j]에는 옆면의 i번째 값과 앞면의 j번째 값 중 작은 값을 골라주면 된다.
#include<bits/stdc++.h>
using namespace std;
int a[101], b[101], A[101][101], ans[101][101];
int main(void) {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int n, m, h; cin >> n >> m >> h;
for (int i = 1; i <= m; i++) cin >> a[i];
for (int i = 1; i <= n; i++) cin >> b[i];
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) cin >> A[i][j];
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (A[i][j] == 1) ans[i][j] = min(a[j], b[i]);
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) cout << ans[i][j] << ' ';
cout << '\n';
}
}
1153C. Serval and Paranthesis Sequence (*1700)
'(', ')', '?'로 이루어진 문자열이 주어지고, '?'자리에는 '('와 ')'가 올 수 있다.
전체 문자열이 'correct parenthesis sequence'가 되어야 하고, prefix들은 되면 안 된다.
따라서 먼저, 문자열의 길이가 홀수이면 correct할 수 없고, 주어지는 문자열에서 '('의 개수가 절반을 넘거나 ')'의 개수가 절반을 넘어도 correct할 수 없다.
이 경우들을 모두 제거해주고, prefix들이 correct할 수 없도록 '?'를 앞에서부터 최대한 '('로 바꿔준다.
최종적으로 바꾼 후에 만들어진 문자열이 문제 조건을 만족하는지 다시 체크해준다.
#include<bits/stdc++.h>
using namespace std;
int main(void) {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int n; cin >> n;
string s; cin >> s;
if (n % 2) return cout << ":(", 0;
int l = 0, r = 0;
for (int i = 0; i < n; i++) {
if (s[i] == '(') l++;
else if (s[i] == ')') r++;
}
if (l > n / 2 || r > n / 2) return cout << ":(", 0;
for (int i = 0; i < n; i++) {
if (s[i] == '?') {
if (l < n / 2) {
s[i] = '(';
l++;
}
else s[i] = ')';
}
}
int cnt = 0;
for (int i = 0; i < n; i++) {
if (s[i] == '(') cnt++;
else {
cnt--;
if (i != n - 1 && cnt <= 0) return cout << ":(", 0;
}
}
cout << s;
}
1153D. Serval and Rooted Tree (*1900)
이 문제의 풀이를 이해하는데만 1시간 넘게 걸린 것 같다. 좋은 문제임에 틀림없지만 너무 어렵다...
문제를 요약하자면, k개의 리프노드에 1부터 k까지 하나씩 부여를 할 수 있다.
그리고 각 노드별로 min인지 max인지 주어져있고, min인 경우에는 자신의 자식들 중 최솟값을 가져오고 max인 경우에는 최댓값을 가져온다.
최종적으로 루트노드인 1번 노드가 가질 수 있는 최댓값을 구하는 것이다.
핵심적인 아이디어는, min과 max에 관계없이 자신이 최대가 되기 위해서는, 자식들의 값이 최대가 될수록 좋다는 것이다.
그러기 위해서 min을 취했을 때와 max를 취했을 때 자손들에서 지워지게 되는 노드의 수를 구한다.
문제의 예시를 확인해보자.
먼저, 리프노드에 적혀있는 max와 min은 아무 의미 없으므로 고려하지 않는다.
3번 노드만 따로 보면, min이기 때문에 자식 노드의 값 중에서 최솟값을 가져온다.
이때, 자식노드인 6, 7, 8번 노드에 배정되는 값을 각각 a, b, c라고 해보자.
일반성을 잃지 않고 a < b < c라고 가정하면, 3번 노드에는 a가 배정되게 된다.
따라서 b와 c는 절대 1번 노드의 값이 될 수 없다.
즉, 어떤 숫자가 배정되는지와 상관없이 3번 노드로 올라올 땐 2개의 수는 제외되고,
1번 노드가 최대가 되기 위해서는 3번 노드가 클수록 좋으며,
3번 노드가 최대가 되기 위해서는 제외되는 수인 b와 c가 최대한 작아질수록 좋기 때문에 a+1, a+2가 되는 게 최적이다.
그러므로 3번노드의 최댓값은
리프 노드의 수 - 지워지는 노드의 수 = 리프 노드의 수 - (자식의 수 -1) = 3 - 2 = 1을 만족한다.
이를 임의의 노드에 대해서 정리하면 min이 배정된 노드에서는
(자식 노드를 루트로 하는 서브 트리에서의 지워지는 노드의 수) + (자식 노드 수 - 1) 만큼 지워지게 된다.
max가 배정된 노드에서는 어떨까?
자식들 중 최댓값을 가져와야 하는데, 이 최댓값이 제일 크기 위해서는
자식들을 루트로 하는 서브트리들 중에서 지워지는 노드의 수가 가장 적은 자식을 고르면 된다.
해당 서브트리의 지워지는 노드 수를 m개라고 하면, 해당 서브 트리의 리프 노드에 k ~ k-m+1 값을 각각 부여해주는 게 최적이기 때문이다.
따라서 아래와 같이 코드가 만들어진다.
#include<bits/stdc++.h>
#define sz(x) (int)x.size()
using namespace std;
vector<int>adj[300001];
int flag[300001];
int leaf = 0;
int dfs(int u) {
if (sz(adj[u]) == 0) { //leaf
leaf++;
return 0; //지워주는 노드 x
}
int res = (flag[u]? 1e6 : 0);
//min인 경우에는 지워지는 노드들의 합, max인 경우에는 지워지는 노드의 최솟값
for (int v : adj[u]) {
if (flag[u]) res = min(res, dfs(v));
else res += dfs(v);
}
//min인 경우에는 자식들 중 1개를 제외하고 모두 지워지므로 해당 개수 추가
return (flag[u] ? res : res + sz(adj[u])-1);
}
int main(void) {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int n; cin >> n;
for (int i = 1; i <= n; i++) cin >> flag[i];
for (int i = 1; i < n; i++) {
int a; cin >> a;
adj[a].push_back(i + 1);
}
int k = dfs(1);
cout << leaf - k;
}
'프로그래밍 대회 풀이 > Codeforces' 카테고리의 다른 글
[Codeforces] Round #552 (Div. 3) A ~ E 풀이 (0) | 2021.01.11 |
---|---|
[Codeforces] Round #694 (Div. 2) 풀이 (0) | 2021.01.07 |
[Codeforces] Educational Round 76 (A ~ E) 풀이 (2) | 2021.01.03 |
Codeforces Round #690 (Div. 3) 풀이 (0) | 2020.12.16 |
Round #686 (Div. 3) 후기 및 풀이 (8) | 2020.11.25 |