A - Captain Flint and Crew Recruitment
정수 \(n\)이 주어진다.
nearly prime은 서로 다른 두 소수의 곱으로 나타낼 수 있는 정수를 말한다.
\(n\)을 서로 다른 4개의 양의 정수의 합으로 나타내야 하는데, 그 중 적어도 3개가 nearly prime일 수 있는지 여부를 알아내고,
가능하다면 실해를 출력해야 한다.
가장 작은 3개의 nearly prime인 6, 10, 14와 \(n-30\)을 하면 일반적으로 답이다.
\(n-30\)이 6, 10, 또는 14와 같거나 양의 정수가 아닐 경우 각각 예외처리를 해주면 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
ll gcd(ll a, ll b) { for (; b; a %= b, swap(a, b)); return a; }
int main()
{
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int t; cin >> t;
while (t--)
{
int n; cin >> n;
if (n < 31) cout << "NO\n";
else
{
cout << "YES\n";
if (n - 30 == 6)
{
cout << "5 6 10 15\n";
}
else if (n - 30 == 10)
{
cout << "6 9 10 15\n";
}
else if (n - 30 == 14)
{
cout << "6 7 10 21\n";
}
else
{
cout << "6 10 14 " << n - 30 << '\n';
}
}
}
}
|
B - Captain Flint and a Long Voyage
\(n\)자리로 이루어진 양의 정수 \(x\)가 주어진다.
이 정수의 각각의 자리를 이진수로 바꾸고, 이를 \(k\)라고 하자.
마지막으로 \(k\)의 마지막 \(n\)자리를 삭제했을 때, 이 값이 최대가 되는 \(n\)중 최소값을 알아내야 한다.
우선 각 자리수를 이진수로 바꿨을 때 길이가 길수록 이득임을 알 수 있다. 따라서 각 자리는 8또는 9여야 한다.
\(k\) 마지막 \(n\)자리를 삭제할 때 영향을 받는 자리수는 8, 그렇지 않는 자리수는 9로 하면 답이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
ll gcd(ll a, ll b) { for (; b; a %= b, swap(a, b)); return a; }
int main()
{
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int t; cin >> t;
while (t--)
{
int n; cin >> n;
int er = (n - 1) / 4 + 1;
for (int i = 0; i < n; i++)
{
if (i + er < n) cout << 9;
else cout << 8;
}
cout << '\n';
}
}
|
C - Uncle Bogdan and Country Happiness
\(n\)개의 정점으로 이루어진 트리가 있다. 1번 정점이 루트이다.
\(m\)명의 사람들이 있고, 사람들은 1번 정점에서 일을 한 다음 본인의 집이 있는 정점으로 이동한다.
각각의 사람들은 퇴근할 때 기분이 좋을 수도 있고, 나쁠 수도 있다.
또 퇴근길에 정점 사이를 이동하면서, 기분이 좋았던 사람이 기분이 나빠질 수도 있다.
한 번 기분이 나빠진 다음에는 다시 기분이 좋아지지 않는다.
각 정점에 대해 행복도 \(h_i\)가 주어진다.
이 값은 퇴근길에 \(i\)번 정점을 들른 모든 사람에 대해, 이 정점에 있을 때 기분이 좋았던 사람의 수에서 기분이 나빴던 사람의 수를 뺀값이다.
각 정점이 집인 사람의 수들이 주어졌을 때, 모든 정점 \(i\)에 대하여 행복도 \(h_i\)가 되도록 하는것이 가능한지 알아내야 한다.
반대로, 리프에서부터 루트까지 올라가면서 문제를 해결해 보자.
초기에 사람들은 모두 기분이 좋지 않고, 중간에 올라가면서 기분이 좋아질 수 있다.
현재 어떤 리프노드에 대해, 사람 수가 부족하거나 이미 행복한 사람들이 있는 등 현재 사람들로 각 정점의 행복도를 만들 수 없다면 불가능하다.
각 리프 노드를 처리했으면 이 노드를 삭제하고, 다른 리프노드를 골라서 루트 노드를 처리할 때까지 반복하면 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
ll gcd(ll a, ll b) { for (; b; a %= b, swap(a, b)); return a; }
int n, m;
int p[100001];
int h[100001];
vector <int> graph[100001];
int par[100001];
int child[100001];
int cgood[100001], cbad[100001];
void DFS(int v, int pr)
{
par[v] = pr;
child[v] = 0;
cgood[v] = 0, cbad[v] = p[v];
for (int nv : graph[v])
{
if (nv == pr) continue;
child[v]++;
DFS(nv, v);
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int t; cin >> t;
while (t--)
{
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> p[i];
for (int i = 1; i <= n; i++) cin >> h[i];
for (int i = 1; i <= n; i++) graph[i].clear();
for (int i = 0; i < n - 1; i++)
{
int u, v; cin >> u >> v;
graph[u].push_back(v);
graph[v].push_back(u);
}
DFS(1, 0);
bool ans = true;
queue <int> q;
for (int i = 1; i <= n; i++) if (child[i] == 0) q.push(i);
while (!q.empty())
{
int v = q.front(); q.pop();
int ch = cgood[v] - cbad[v];
int mx = cgood[v] + cbad[v];
if (h[v] < ch || h[v] > mx || (h[v] - ch) % 2 == 1)
{
ans = false;
break;
}
int inv = (h[v] - ch) / 2;
cgood[v] += inv;
cbad[v] -= inv;
if (par[v] && --child[par[v]] == 0) q.push(par[v]);
cgood[par[v]] += cgood[v];
cbad[par[v]] += cbad[v];
}
if (ans) cout << "YES\n";
else cout << "NO\n";
}
}
|
D - Captain Flint and Treasure
\(n\)의 길이를 가지는 배열 \(a,b\)가 있다.
초기에 \(ans\)변수에 0이 할당되어있고, 다음의 연산을 할 수 있다.]
1. 인덱스 \(i\)를 고른다.
2. \(a_i\)를 \(ans\)에 더한다.
3. \(b_i\)가 -1이 아니라면 \(a_i\)를 \(a_{b_i}\)에 더한다.
각각의 인덱스 \(i\)를 한 번씩 고를 수 있을 때, 얻을 수 있는 \(ans\)값의 최대값을 알아내야 한다.
문제를 \(i\)의 부모가 \(b_i\)인 포레스트로 생각해보자.
만약 \(a_i\)가 전부 양수라면, 리프노드 부터 시작해서 최대한 같은 수를 여러번 더하는 것이 이득임을 알 수 있다.
C번과 같이 리프노드부터 시작해 문제를 해결하자.
현재 \(a_i\)에 저장된 값이 음수가 아니라면, 바로 \(ans\)에 \(a_i\)를 더한다. \(a_{b_i}\)에 \(a_i\)를 더한다.
하지만 음수라면, 이 수를 여러번 더하는 것은 이득이 될 수 없기때문에, 지금 계산하는 것은 무조건 손해이다.
따라서 \(a_i\)가 음수인 모든 점은 음수가 아닌 점이 모두 계산된 후에, 만난 순서의 역순으로 처리하면 무조건 한 번씩만 계산되도록 할 수 있고, 이 방법이 최선임을 알 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
ll gcd(ll a, ll b) { for (; b; a %= b, swap(a, b)); return a; }
ll n;
ll a[200001];
ll b[200001];
int par[200001];
int child[200001];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++)
{
int b; cin >> b;
par[i] = b;
child[b]++;
}
queue <int> q;
for (int i = 1; i <= n; i++) if (child[i] == 0) q.push(i);
ll ans = 0;
vector <int> p;
vector <int> inv;
while (!q.empty())
{
int v = q.front(); q.pop();
ans += a[v];
if (a[v] >= 0)
{
p.push_back(v);
if (par[v] != -1) a[par[v]] += a[v];
}
else
{
inv.push_back(v);
}
if (par[v] != -1 && --child[par[v]] == 0) q.push(par[v]);
}
reverse(inv.begin(), inv.end());
cout << ans << '\n';
for (int v : p) cout << v << ' ';
for (int v : inv) cout << v << ' ';
}
|
E - Uncle Bogdan and Projections
추가 예정
'문제 풀이 > Codeforces' 카테고리의 다른 글
Codeforces Round #662 (Div. 2) (1) | 2020.08.08 |
---|---|
Codeforces Round #661 (Div. 3) (0) | 2020.08.06 |
Educational Codeforces Round 92 (0) | 2020.07.30 |
Codeforces Round #658 (Div. 1, Div. 2) (0) | 2020.07.22 |
Codeforces Round #656 (Div. 3) (0) | 2020.07.18 |