본문 바로가기

문제 풀이/그외

Round A 2021 - Kick Start 2021

K-Goodness String

 

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\)길이의 문자열 \(s\)가 주어진다.

이 문자열의 점수를 \(s_i \ne s_{n-i+1}\)를 만족하는 \(i\)의 개수라고 하자. (\(1 \le i \le n/2\))

문자열의 점수를 \(k\)로 만들기 위해, 바꿔야 하는 문자의 최소 개수를 구해야 한다.

 

 

주어지는 문자열의 원래 점수가 \(ck\)라고 하면, \(|ck-k|\)가 답이다.

 

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
#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, k;
string s;
 
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 >> k;
        cin >> s;
 
        int ck = 0;
        for (int i = 0; i < n / 2; i++)
            if (s[i] != s[n - 1 - i]) ck++;
 
        int res = k - ck;
        if (res < 0) res = -res;
 
        cout << "Case #" << tc << ": " << res << '\n';
    }
}

L Shaped Plots

 

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

\(r \times c\)크기의 격자가 있다.

격자의 값은 0또는 1이다.

 

이 격자에서 문제에서 말하는 "L-모양"이 몇개 있는지 알아내야 한다.

 

각각의 칸에서 시작해서, 왼쪽/오른쪽/위쪽/아래쪽으로 최대 몇 칸까지 연결되어 있는지 간단한 dp로 저장해 놓을 수 있다.

이를 이용해 계산해 주면 된다.

 

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
#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 int N = 1005;
 
int r, c;
int board[N][N];
 
ll psum_r[N][N];
ll psum_l[N][N];
ll psum_d[N][N];
ll psum_u[N][N];
 
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 >> r >> c;
        for (int i = 1; i <= r; i++for (int j = 1; j <= c; j++)
            cin >> board[i][j];
 
        for (int i = 0; i <= r + 1; i++for (int j = 1; j <= c + 1; j++)
        {
            psum_r[i][j] = 0;
            psum_l[i][j] = 0;
            psum_d[i][j] = 0;
            psum_u[i][j] = 0;
        }
 
        for (int i = 1; i <= r; i++)
        {
            for (int j = 1; j <= c; j++)
            {
                if (board[i][j] == 0continue;
                psum_l[i][j] = psum_l[i][j - 1+ 1;
            }
 
            for (int j = c; j >= 1; j--)
            {
                if (board[i][j] == 0continue;
                psum_r[i][j] = psum_r[i][j + 1+ 1;
            }
        }
 
        for (int j = 1; j <= c; j++)
        {
            for (int i = 1; i <= r; i++)
            {
                if (board[i][j] == 0continue;
                psum_u[i][j] = psum_u[i - 1][j] + 1;
            }
 
            for (int i = r; i >= 1; i--)
            {
                if (board[i][j] == 0continue;
                psum_d[i][j] = psum_d[i + 1][j] + 1;
            }
        }
 
        ll ans = 0;
        for (int i = 1; i <= r; i++for (int j = 1; j <= c; j++)
        {
            if (psum_l[i][j] >= 4)
            {
                ll r1 = min(psum_l[i][j] / 2 - 1, max(0ll, psum_u[i][j] - 1));
                ll r2 = min(psum_l[i][j] / 2 - 1, max(0ll, psum_d[i][j] - 1));
 
                ans += r1;
                ans += r2;
            }
 
            if (psum_r[i][j] >= 4)
            {
                ll r1 = min(psum_r[i][j] / 2 - 1, max(0ll, psum_u[i][j] - 1));
                ll r2 = min(psum_r[i][j] / 2 - 1, max(0ll, psum_d[i][j] - 1));
 
                ans += r1;
                ans += r2;
            }
 
            if (psum_u[i][j] >= 4)
            {
                ll r1 = min(psum_u[i][j] / 2 - 1, max(0ll, psum_l[i][j] - 1));
                ll r2 = min(psum_u[i][j] / 2 - 1, max(0ll, psum_r[i][j] - 1));
 
                ans += r1;
                ans += r2;
            }
 
            if (psum_d[i][j] >= 4)
            {
                ll r1 = min(psum_d[i][j] / 2 - 1, max(0ll, psum_l[i][j] - 1));
                ll r2 = min(psum_d[i][j] / 2 - 1, max(0ll, psum_r[i][j] - 1));
 
                ans += r1;
                ans += r2;
            }
        }
 
        cout << "Case #" << tc << ": " << ans << '\n';
    }
}

Rabbit House

 

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

\(r \times c\)크기의 격자가 있다. 각 격자의 초기 높이가 주어진다.

인접한 격자의 높이 차이가 1보다 작거나 같도록 하기 위해, 각 격자에서 추가로 높여야 하는 높이의 합의 최소값을 구해야 한다.

 

가장 높은 칸에 대해 생각해보자. 이 칸의 높이는 \(h\)이다.

먼저, 이 칸을 추가로 높일 필요는 없다는 사실을 알 수 있다.

그리고 가장 높은 칸과 인접한 칸들은, 적어도 \(h-1\)의 높이를 가져야 함을 알 수 있다.

만약 이보다 높이가 낮다면, 높이를 \(h-1\)로 바꿔준다.

 

그리고 남은 칸들 중에서 가장 높은 칸을 찾아, 이를 반복하면 된다.

set이나 priority queue등의 자료구조를 이용하면 \(O(rc\log rc)\)에 이를 해결할 수 있다.

 

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
#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 r, c;
ll g[301][301];
ll res[301][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++)
    {
        priority_queue<pair<ll, pii> > pq;
 
        cin >> r >> c;
        for (int i = 0; i < r; i++for (int j = 0; j < c; j++)
        {
            cin >> g[i][j];
            res[i][j] = g[i][j];
 
            pq.push({ g[i][j], {i, j} });
        }
 
        ll ans = 0;
 
        while (!pq.empty())
        {
            auto it = pq.top(); pq.pop();
            ll v = it.first;
            int x = it.second.first, y = it.second.second;
 
            if (res[x][y] > v) continue;
 
            for (int k = 0; k < 4; k++)
            {
                int nx = x + "0121"[k] - '1';
                int ny = y + "1012"[k] - '1';
 
                if (nx < 0 || nx >= r || ny < 0 || ny >= c) continue;
                if (res[nx][ny] >= v - 1continue;
 
                ans += v - 1 - res[nx][ny];
                res[nx][ny] = v - 1;
 
                pq.push({ v - 1,{nx, ny} });
            }
        }
 
        cout << "Case #" << tc << ": " << ans << '\n';
    }
}

Checksum

 

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 \times n\)크기의 이진 행렬 \(a\)가 있다.

이 행렬이 바이러스로 인해 손상되어서, 일부 원소가 원래 무엇이었는지 알 수 없게 되었다.

다행히도 각 행과 각 열에 있는 원소들의 XOR값을 저장해 두었기 때문에, 이를 이용해 어느정도 복원이 가능하다.

또, 이를 이용해서도 복원이 불가능하다면, \(b_{i, j}\)의 비용으로 임의의 칸을 복원할 수도 있다.

 

행렬을 모두 복원하는데 필요한 최소 비용을 구해야 한다.

 

 

먼저, 단순히 복원 가능 여부를 알기 위해서는 XOR값은 전혀 쓸모 없다는 사실을 알 수 있다.

각 열과 행 자체를 정점으로 하고, \(a_{i, j}\)가 훼손되었다면 \(i\)번째 열과 \(j\)번째 행을 잇는 간선으로 하는 그래프를 생각해보자.

 

임의의 칸 복원 없이 행렬이 복원될 수 있으려면, 이 그래프에 사이클이 없어야 된다는 사실을 알 수 있다.

 

각 간선의 가중치를 \(B_{i, j}\)로 설정하자.

최소한의 간선을 제거하여 사이클이 없도록 만들기 위해서는, 남은 간선들이 Maximum Spanning Forest가 되어야 한다는 사실을 알 수 있다.

 

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
#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;
int a[501][501];
int b[501][501];
int r[501];
int c[501];
 
int par[1001];
int getPar(int x)
{
    if (par[x] == x) return x;
    return par[x] = getPar(par[x]);
}
bool merge(int a, int b)
{
    a = getPar(a), b = getPar(b);
    if (a == b) return false;
    par[a] = b;
    return true;
}
 
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
 
    int t; cin >> t;
    for (int tc = 1; tc <= t; tc++)
    {
        vector<pair<ll, pii> > v;
 
        ll ans = 0;
 
        cin >> n;
        for (int i = 0; i < n + n; i++) par[i] = i;
 
        for (int i = 0; i < n; i++for (int j = 0; j < n; j++)
            cin >> a[i][j];
        for (int i = 0; i < n; i++for (int j = 0; j < n; j++)
            cin >> b[i][j], ans += b[i][j];
        for (int i = 0; i < n; i++cin >> r[i];
        for (int i = 0; i < n; i++cin >> c[i];
 
        for (int i = 0; i < n; i++for (int j = 0; j < n; j++)
        {
            if (a[i][j] != -1continue;
            v.push_back({ b[i][j], {i, j + n} });
        }
 
        sort(v.rbegin(), v.rend());
        for (auto it : v)
        {
            ll w = it.first;
            int i = it.second.first, j = it.second.second;
 
            if (merge(i, j)) ans -= w;
        }
 
        cout << "Case #" << tc << ": " << ans << '\n';
    }
}

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

SCPC 2021 Round 1  (2) 2021.07.17
Code Jam - Qualification Round 2021  (1) 2021.03.28
Google Kick Start - Round F 2020  (0) 2020.09.27
Google Kick Start - Round E 2020  (2) 2020.08.23
SCPC 2020 Round 1  (2) 2020.08.22