Post

Atto Round 1 (Codeforces Round 1041, Div. 1 + Div. 2) 후기

- Atto Round 1 (Codeforces Round 1041, Div. 1 + Div. 2) 후기

Atto Round 1 (Codeforces Round 1041, Div. 1 + Div. 2) 후기

A. Mix Mex Max

풀이 보기

풀이

조건을 나누어 하나씩 생각해보자.

  • $0$이 배열 안에 존재한다 : $MIN = 0$이 된다. 즉 $MEX = MAX$
    • case work를 해보면 알겠지만, $MEX$와 $MAX$는 같을 수 없다. 즉 $0$이 배열에 있다면 불가능한 경우
    • 결국 $0$이 없기 때문에 항상 $MEX=0$이 된다. 즉 $MAX = MIN$이어야 한다

결론적으로, $MAX=MIN$이기 위해서는 배열에 모두 $0$이 아닌 같은 수로만 채워져있어야 한다!

코드

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
#include <stdio.h>

int main() {
    int T;
    if (scanf("%d", &T) != 1) return 0;
    while (T--) {
        int n;
        scanf("%d", &n);
        int v = -1;
        int ok = 1;
        for (int i = 0; i < n; i++) {
            int a;
            scanf("%d", &a);
            if (a != -1) {
                if (a == 0) {
                    ok = 0;
                } else if (v == -1) {
                    v = a;
                } else if (a != v) {
                    ok = 0;
                }
            }
        }
        puts(ok ? "YES" : "NO");
    }
    return 0;
}

B. Hamiiid, Haaamid… Hamid?

풀이 보기

풀이

Hamid는 항상 같은 방향으로만 진행하는게 이득이다. Mani는 그럼 Hamid를 최대한 막으려고 한다.

Hamid의 입장에서 생각해보자. 왼쪽에 벽 3개, 오른쪽에 벽 1개가 있다면 오른쪽으로 이동하는 것이 최선일 것이다. 그렇다면 Mani는 오른쪽에 벽을 설치하는 것이 최선의 전략이 된다.

Mani가 벽을 먼저 설치한다는 것을 생각하자. 벽이 설치된 후 Hamid가 최선의 선택을 하게 된다. 이 때 최선의 선택은 도착지점에 더 가까운 방향이 될 것이다. 벽을 제외하고 더 가까운 쪽을 선택하는 이유는, 이후부터 Mani가 그 방향으로 계속 벽을 설치할 수 있기 때문에, 걸리는 시간이 거리와 같아지기 때문이다.

하지만, Mani가 벽을 처음에 하나만 설치할 수 있기 때문에, 처음 단계에서는 Hamid가 왼쪽 또는 오른쪽으로 벽이 없는 곳까지 이동 가능하다는 점이다. 이정도 고려해서 개수를 세면 답을 얻을 수 있다.

코드

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
#include <stdio.h>

#define MAX_IDX (int)(2e5 + 1)
const int NONE = -1;

char grid[MAX_IDX + 1];
int n;
int x;

const int WALL = '#';
const int EMPTY = '.';

#define min(a, b) (((a) > (b)) ? (b) : (a))
#define max(a, b) (((a) > (b)) ? (a) : (b))

int main() {
    int t;
    scanf("%d", &t);

    while (t--) {
        scanf("%d %d", &n, &x);
        --x;
        scanf("%s", grid);

        // left
        int first_left = -1;
        int left_empty = 0;
        for (int i = 0; i < x; ++i) {
            if (grid[i] == WALL) {
                first_left = i;
            } else {
                ++left_empty;
            }
        }

        // right
        int first_right = n;
        int right_empty = 0;
        for (int i = n - 1; i > x; --i) {
            if (grid[i] == WALL) {
                first_right = i;
            } else {
                ++right_empty;
            }
        }

        // first case
        if (first_left == NONE && first_right == NONE) {
            printf("1\n");
        } else {
            int left_ret = 1;
            int right_ret = 1;

            // left place
            if (left_empty > 0) {
                left_ret = min(x, (n - first_right)) + 1;
            } else {
                left_ret = min(x, (n - x - 1)) + 1;
            }

            // right place
            if (right_empty > 0) {
                right_ret = min(first_left + 1, (n - x - 1)) + 1;
            } else {
                right_ret = min(x, (n - x - 1)) + 1;
            }

            // cmp
            int ret = max(left_ret, right_ret);
            printf("%d\n", ret);
        }
    }
    return 0;
}

C. Trip Shopping

풀이 보기

풀이

두 배열 $a, b$가 있을 때, 선택한 인덱스 $i, j$에 대해서 4개의 값을 임의배치하여 각 플레이어들이 원하는 결과를 얻도록 하는 문제이다. 우리는 Ali의 관점이며, 점수 $v$를 최소화하는 것이 목표이다.

Bahamin의 목표가 선택된 인덱스에 대해 $v$의 최대화이다. 이 때 Bahamin은 목표를 위해 배열을 변경하거나 가만히 둘 수도 있다. 이 때 $v$는 항상 커지거나 같다. 작아지지 않는다.

Ali의 입장에서 생각해보자. 인덱스를 선택한다는 것은 $v$가 커지는 위험을 항상 동반하는 꼴이다. 이 과정을 총 $k$번 진행해야한다. 어떤 방법이 Ali의 입장에서 최선의 인덱스 선택일까? 정답은 $v$의 증가를 최소화하는 인덱스를 계속 선택하는 것이다. Bahamin은 $v$를 최대화하도록 배열을 변경할 것이지만, 이후부터는 계속 배열을 그대로 두어야 한다. 이미 최적의 상황으로 맞춰두었기 때문. 즉, $k$번의 라운드를 진행하는 것이 의미가 없다!

결국 Ali가 “$v$가 증가를 최소로 하는” 인덱스 $i, j$를 찾는 과정 1번만 필요하다는 것이다. 다만 수의 범위 때문에 완전탐색으로는 찾을 수 없다. 여기서 찾은 방법이 $a+b$가 제일 작은 친구들 위주로 선택하는 것. 그러면 같은 순서더라도 숫자들이 작은 애들이 더 유리하다는 것은 자명하다. 여기서 $v$의 증가량을 계산하고, 그들 중 제일 작은 인덱스를 추려내면 된다.

코드

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
#include <stdio.h>
#include <stdlib.h>

typedef long long ll;

#define MAX_IDX (int)(2e5)
const ll INF = (ll)987654321987654321;

ll a[MAX_IDX];
ll b[MAX_IDX];
ll vpair[MAX_IDX];
int n, k;

ll absll(ll x) {
    return (x < 0) ? -x : x;
}

typedef struct {
    ll a, b;
    ll vdiff;
} Pair;

Pair p[MAX_IDX];

ll read_input() {
    ll v = 0;
    scanf("%d %d", &n, &k);
    for (int i = 0; i < n; ++i)
        scanf("%lld", &a[i]);
    for (int i = 0; i < n; ++i) {
        scanf("%lld", &b[i]);
        vpair[i] = absll(a[i] - b[i]);
        v += vpair[i];

        p[i].a = a[i];
        p[i].b = b[i];
        p[i].vdiff = vpair[i];
    }
    return v;
}

ll max_permuted_cost(ll x1, ll x2, ll x3, ll x4) {
    ll vals[4] = {x1, x2, x3, x4};
    for (int i = 3; i > 0; --i)
        for (int j = 0; j < i; ++j)
            if (vals[j] > vals[j + 1]) {
                ll tmp = vals[j];
                vals[j] = vals[j + 1];
                vals[j + 1] = tmp;
            }
    return (vals[3] - vals[0]) + (vals[2] - vals[1]);
}

int cmp(const void* x, const void* y) {
    const Pair* px = (const Pair*)x;
    const Pair* py = (const Pair*)y;
    
    ll sum_x = px->a + px->b;
    ll sum_y = py->a + py->b;
    return (sum_x > sum_y) - (sum_x < sum_y);
}

int main() {
    int t;
    scanf("%d", &t);

    while (t--) {
        ll v = read_input();

        qsort(p, n, sizeof(Pair), cmp);

        ll min_delta = INF;
        for (int i = 0; i < n - 1; ++i) {
            ll cur_v = absll(p[i].a - p[i].b) + absll(p[i + 1].a - p[i + 1].b);
            ll new_v = max_permuted_cost(p[i].a, p[i + 1].a, p[i].b, p[i + 1].b);
            if (new_v - cur_v < min_delta)
                min_delta = new_v - cur_v;
        }

        printf("%lld\n", v + min_delta);
    }
    return 0;
}

결과

ContestStart timeRankSolvedRating changeNew rating
#1041 (Div. 1 + Div. 2)2025/8/7 23:3548503-191462
This post is licensed under CC BY 4.0 by the author.