본문 바로가기

문제 풀이/그외

Google Kick Start - Round E 2020

아깝다

Longest Arithmetic

 

Kick Start - Google’s Coding Competitions

Hone your coding skills with algorithmic puzzles meant for students and those new to coding competitions. Participate in one round or join them all.

codingcompetitions.withgoogle.com

어떤 배열이 2개 이상의 원소를 가지고, 인접한 두 원소의 차이가 모두 같다면, 이 배열을 arithmetic array라고 한다.

 

\(n\)길이의 배열이 주어지고, 이 배열의 부분 배열중 arithmetic array인 것들 중에 가장 긴것의 길이를 알아내야 한다.

 

 

단순 구현문제이다. 하라는대로 하면 된다.

 

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 long long ll;
typedef pair<intint> pii;
typedef pair<ll, ll> pll;
 
ll gcd(ll a, ll b) { for (; b; a %= b, swap(a, b)); return a; }
 
int n;
ll a[200001];
 
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
 
    int T; cin >> T;
    for (int tc = 1; tc <= T; tc++)
    {
        cin >> n;
        for (int i = 0; i < n; i++cin >> a[i];
 
        int ans = 0;
        int cnt = 1;
        ll cd = a[1- a[0];
        for (int i = 2; i < n; i++)
        {
            if (a[i] - a[i - 1== cd) cnt++;
            else
            {
                ans = max(ans, cnt);
                cnt = 1;
                cd = a[i] - a[i - 1];
            }
        }
 
        ans = max(ans, cnt);
 
        cout << "Case #" << tc << ": " << ans + 1 << '\n';
    }
}

High Buildings

 

Kick Start - Google’s Coding Competitions

Hone your coding skills with algorithmic puzzles meant for students and those new to coding competitions. Participate in one round or join them all.

codingcompetitions.withgoogle.com

\(n\)개의 빌딩이 일직선으로 서있다.

가장 왼쪽에 서 있는 빌딩의 왼쪽에서 이 빌딩들을 바라봤을 때 \(a\)채의 빌딩이 보였고,

가장 오른쪽에 서 있는 빌딩의 오른쪽에서 이 빌딩들을 바라봤을 때 \(b\)채의 빌딩이 보였다.

또, 어느쪽에서 보든 상관없이 보이는 빌딩의 수는 \(c\)채이다.

 

어떤 빌딩이 보이기 위에서는, 내 시야와 그 빌딩사이에 더 높은 빌딩이 없어야 한다.

빌딩의 높이가 1이상 \(n\)이하의 정수라고 할 때, 이 정보를 토대로 가능한 빌딩 높이를 하나 알아내야 한다.

또는, 불가능함을 알아내야 한다.

 

우선 가운데 \(c\)채의 빌딩을 \(n\)높이로 놓자.

그리고 그 왼쪽으로 \(a-c\)채의 빌딩을 높이를 1씩 줄여가면서 놓고,

오른쪽으로 \(b-c\)채의 빌딩을 높이를 1씩 줄여가면서 놓자.

 

총 빌딩이 아직 \(n\)채가 안됬다면, 높이가 1인 빌딩을 적당히 중간에 껴놓으면 된다.

도중에 불가능한 경우가 생기면, 조건을 만족하는 경우도 없다.

 

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
#include <bits/stdc++.h>
using namespace std;
 
typedef long long ll;
typedef pair<intint> pii;
typedef pair<ll, ll> pll;
 
ll gcd(ll a, ll b) { for (; b; a %= b, swap(a, b)); return a; }
 
int n, a, b, c;
vector <int> ans;
 
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
 
    int T; cin >> T;
    for (int tc = 1; tc <= T; tc++)
    {
        cin >> n >> a >> b >> c;
 
        cout << "Case #" << tc << ": ";
 
        if (a + b - c > n)
        {
            cout << "IMPOSSIBLE\n";
            continue;
        }
 
        ans.clear();
 
        for (int i = 0; i < a - c; i++) ans.push_back(n - (a - c) + i);
        for (int i = 0; i < c; i++) ans.push_back(n);
        for (int i = 0; i < b - c; i++) ans.push_back(n - 1 - i);
 
        int tmp = -1;
        for (int i = 1; i < ans.size(); i++)
        {
            bool f1 = false, f2 = false;
            for (int j = 0; j < i; j++)
            {
                if (ans[j] > 1) f1 = true;
            }
 
            for (int j = i; j < ans.size(); j++)
            {
                if (ans[j] > 1) f2 = true;
            }
 
            if (f1 && f2)
            {
                tmp = i;
                break;
            }
        }
 
        if (tmp == -1 && n - (a + b - c) > 0)
        {
            cout << "IMPOSSIBLE\n";
            continue;
        }
 
        for (int i = 0; i < ans.size(); i++)
        {
            if (i == tmp)
            {
                for (int i = 0; i < n - (a + b - c); i++cout << "1 ";
            }
            cout << ans[i] << ' ';
        }
 
        cout << '\n';
    }
}

Toys

 

Kick Start - Google’s Coding Competitions

Hone your coding skills with algorithmic puzzles meant for students and those new to coding competitions. Participate in one round or join them all.

codingcompetitions.withgoogle.com

아기가 \(n\)개의 장난감을 가지고 놀려고 한다.

장난감은 원형으로 늘어서 있고, 1번 장난감부터 가지고 놀기 시작해서 시계방향으로 있는 장난감을 차례로 가지고 놀게 된다.

\(i\)번 장난감을 가지고 놀면, \(e_i\) 시간동안 가지고 논다.

다 논 다음에는, 그 장난감에 대해 \(r_i\) 시간동안 기억한다.

 

만약 어떤 장난감에 대한 기억이 아직 남아있는 상태에서 그 장난감에 도착하게 되면, 놀기를 그만둔다.

장난감에 대한 정보가 주어지면, 장난감을 최대한 적게 제거해서 아기가 놀 수 있는 시간의 최대 길이를 알아내야 한다.

 

 

우선 장난감의 정보와 관계없이, 일단 모든 장난감을 한번씩 가지고 놀게 된다.

 

현재 남아있는 장난감의 모든 \(e_i\)의 합을 \(sum\)이라고 하자.

\(i\)번 장난감에 대해, \(sum - e_i - r_i\)가 0보다 작다면 그 장난감을 2번째로 봤을 때 놀기를 그만두게 된다.

만약 현재 그런 장난감이 여러 가지라면, 번호가 가장 작은 장난감에서 놀기를 그만둘 것이다.

 

따라서 현재 상황에 대해 아기가 놀 수 있는 최대 시간을 계산하고, 아기가 놀기 그만두는 장난감을 제거하는 것을 반복하면 된다.

만약 도중에 \(sum - e_i - r_i\)가 0보다 작은 경우가 없다면 무한히 놀 수 있게 되고,

그런 경우가 없다면 지금까지 계산한 최대 시간 중 최대값을 찾으면 된다.

 

구현은 Priority Queue나 Segment Tree등등으로 할 수 있다.

 

 

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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <bits/stdc++.h>
using namespace std;
 
typedef long long ll;
typedef pair<intint> pii;
typedef pair<ll, ll> pll;
 
ll gcd(ll a, ll b) { for (; b; a %= b, swap(a, b)); return a; }
 
ll n;
ll e[100001];
ll r[100001];
 
ll segTree[100001];
void update(int i, ll v)
{
    while (i <= n)
    {
        segTree[i] += v;
        i += i & -i;
    }
}
ll getVal(int i)
{
    ll res = 0;
    while (i)
    {
        res += segTree[i];
        i -= i & -i;
    }
    return res;
}
 
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
 
    int T; cin >> T;
    for (int tc = 1; tc <= T; tc++)
    {
        ll sum = 0;
        memset(segTree, 0sizeof segTree);
 
        cin >> n;
        for (int i = 1; i <= n; i++)
        {
            cin >> e[i] >> r[i];
            update(i, e[i]);
            sum += e[i];
        }
 
        priority_queue<pll> pq;
        for (int i = 1; i <= n; i++)
        {
            pq.push({ r[i] + e[i], i });
        }
 
        priority_queue<int> ni;
        while (!pq.empty())
        {
            ll x = pq.top().first;
            int idx = pq.top().second;
 
            if (sum - x < 0)
            {
                pq.pop();
                ni.push(-idx);
            }
            else break;
        }
 
        ll mxLen = 0;
        int mxCnt = 0;
 
        int cnt = 0;
        while (!ni.empty())
        {
            int idx = -ni.top(); ni.pop();
 
            ll curLen = sum + getVal(idx - 1);
            if (mxLen < curLen)
            {
                mxLen = curLen;
                mxCnt = cnt;
            }
 
            cnt++;
            sum -= e[idx];
            update(idx, -e[idx]);
            while (!pq.empty())
            {
                ll x = pq.top().first;
                int idx = pq.top().second;
 
                if (sum - x < 0)
                {
                    pq.pop();
                    ni.push(-idx);
                }
                else break;
            }
        }
 
        if (pq.size() > 1)
        {
            cout << "Case #" << tc << ": " << cnt << " INDEFINITELY\n";
            continue;
        }
 
        cout << "Case #" << tc << ": " << mxCnt << ' ' << mxLen << '\n';
    }
}

Golden Stone

 

Kick Start - Google’s Coding Competitions

Hone your coding skills with algorithmic puzzles meant for students and those new to coding competitions. Participate in one round or join them all.

codingcompetitions.withgoogle.com

\(n\)개의 정점과 \(m\)개의 간선으로 이루어져 있는 그래프가 있다.

\(s\)개의 원소가 있고, 그래프의 각 정점에는 어떤 원소(들)를 무한히 얻을 수 있는 광산이 있거나, 없다.

\(r\)개의 레시피가 주어진다. 각 레시피는 최대 3개의 원소를 조합해 다른 어떤 원소를 만들 수 있다는 정보를 가지고 있다.

레시피대로 원소를 조합하기 위해서는, 각 원소들이 같은 장소에 있어야 한다.

하나의 원소를 어떤 정점에서 간선으로 이어진 다른 정점으로 옮기는데 1의 에너지가 든다.

 

1번 원소를 제작하기 위해, 사용해야 하는 에너지의 최소값을 구해야 한다.

만약 에너지가 \(10^{12}\)이상 필요하다면 대신 -1을 출력한다.

 

 

정점이 \((k, v)\)의 순서쌍인 그래프를 생각해보자.

각 정점까지의 거리는 \(v\)번 정점에 \(k\)번 원소를 가져오기 위한 (또는 제작하기 위한) 최소 에너지를 나타낸다.

 

광산이 있는 정점들에 대해, 그 원소를 만드는데 필요한 에너지가 0이라고 생각하고, 다익스트라를 이용해 최단거리를 계산해보자.

 

어떤 정점 \((k, v)\)를 보고 있다면 다음 정점들에 대해 완화를 시도할 수 있다.

\((k, u)\): 원래 그래프의 정점 \((u, v)\)사이에 간선이 존재한다면, (\((k,v)\)까지의 거리 + 1)로 완화를 시도할 수 있다.

\((l, v)\): \(k\)번 원소가 \(l\)번 원소를 만드는 레시피에 필요한 원소라면, \(v\)번 정점에서 해당 레시피를 이용해 \(l\)번 원소를 만드는데 필요한 에너지로 완화를 시도할 수 있다.

 

최단거리를 모두 갱신했다면, 1번 원소를 각 정점에서 제작했을 때 필요한 에너지의 최소값을 알 수 있으므로, 이 중 최소값을 구하면 된다.

 

 

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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include <bits/stdc++.h>
using namespace std;
 
typedef long long ll;
typedef pair<intint> pii;
typedef pair<ll, ll> pll;
 
ll gcd(ll a, ll b) { for (; b; a %= b, swap(a, b)); return a; }
 
const ll INF = 1e12;
 
int n, m, s, r;
vector <int> graph[301];
ll dist[301][301];
 
vector <pair<vector<int>int> > rcp;
vector <int> ing[301];
 
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
 
    int T; cin >> T;
    for (int tc = 1; tc <= T; tc++)
    {
        cin >> n >> m >> s >> r;
        for (int i = 1; i <= n; i++) graph[i].clear();
        fill(&dist[0][0], (&dist[n][n]) + 1, INF);
        rcp.clear();
        for (int i = 1; i <= s; i++) ing[i].clear();
 
        for (int i = 0; i < m; i++)
        {
            int u, v; cin >> u >> v;
            graph[u].push_back(v);
            graph[v].push_back(u);
        }
 
        priority_queue<pair<ll, pii> > pq;
        for (int v = 1; v <= n; v++)
        {
            int c; cin >> c;
            for (int j = 0; j < c; j++)
            {
                int k; cin >> k;
                dist[k][v] = 0;
                pq.push({ 0, {k, v} });
            }
        }
 
        for (int i = 0; i < r; i++)
        {
            int c; cin >> c;
            vector <int> tmp;
            for (int j = 0; j < c; j++)
            {
                int k; cin >> k;
                tmp.push_back(k);
                ing[k].push_back(i);
            }
 
            int rs; cin >> rs;
            rcp.push_back({ tmp, rs });
        }
 
        while (!pq.empty())
        {
            ll cd = -pq.top().first;
            int k = pq.top().second.first;
            int v = pq.top().second.second;
            pq.pop();
 
            if (dist[k][v] < cd) continue;
 
            for (int nv : graph[v])
            {
                if (dist[k][nv] > cd + 1)
                {
                    dist[k][nv] = cd + 1;
                    pq.push({ -dist[k][nv], {k, nv} });
                }
            }
 
            for (int idx : ing[k])
            {
                vector <int>& ci = rcp[idx].first;
                int res = rcp[idx].second;
 
                ll rd = 0;
                for (int nk : ci)
                {
                    rd += dist[nk][v];
                }
 
                if (dist[res][v] > rd)
                {
                    dist[res][v] = rd;
                    pq.push({ -dist[res][v], {res, v} });
                }
            }
        }
 
        ll res = *min_element(&dist[1][1], (&dist[1][n]) + 1);
        if (res == INF) res = -1;
 
        cout << "Case #" << tc << ": " << res << '\n';
    }
}

'문제 풀이 > 그외' 카테고리의 다른 글

Round A 2021 - Kick Start 2021  (0) 2021.03.21
Google Kick Start - Round F 2020  (0) 2020.09.27
SCPC 2020 Round 1  (2) 2020.08.22
Google Kick Start - Round D 2020  (0) 2020.07.13
Google Code Jam - Round 1A 2020  (2) 2020.04.11