Home Codeforces Round #728 (Div. 2) 후기
Post
Cancel

Codeforces Round #728 (Div. 2) 후기

조금만 있으면 Expert에 진입할 수 있다. 이번 contest에서 20점만 얻어도 1600점에 도달하여 파란색 닉네임을 달 수 있다.

기합 넣고 가자ㅏㅏㅏㅏ~

A. Pretty Permutations

풀이 보기

풀이

예제만 봤다가 한번 틀린 문제이다.

모든 원소를 한 칸씩만 미루는 것이 정답이 아니다. 만약 $n$개의 원소를 한칸만 미루는 것은 거리가 $2n-2$가 된다. 이것이 최소가 아니었다.

정답은 2개씩 묶어 서로 위치를 바꾸는 방법이다. 만약 원소의 개수가 홀수라면 마지막 남는 3개의 원소는 서로 한칸씩 밀어 모든 원소의 거리가 1이 되도록 조정할 수 있는 방법이 있다. 이 방법을 이용하면 거리가 $n$인 방법으로 모든 원소의 자리를 바꿀 수 있다.

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        int n;
        scanf("%d", &n);
        int a = n >> 1;
        if ((n & 1) > 0) {
            for (int i = 1; i < a; ++i) {
                printf("%d %d ", i << 1, (i << 1) - 1);
            }
            printf("%d %d %d\n", n - 1, n, n - 2);
        }
        else {
            for (int i = 1; i <= a; ++i) {
                printf("%d %d ", i << 1, (i << 1) - 1);
            }
            printf("\n");
        }
    }
    return 0;
}

B. Pleasant Pairs

풀이 보기

풀이

모든 원소에 대해 검사하면 시간이 부족한 문제이다. 이 문제는 내가 온전히 풀었다고는 말하기 힘든 문제이다.

두 원소의 곱이 두 index의 합과 같음을 찾는 문제인데, 탐색 횟수를 줄이는 방법으로 앞의 원소의 값을 이용했다. 원소는 각각 자연수로 이루어져 있으므로, 두 index의 합 $i+j$는 원소 $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
#include <stdio.h>

#define MAX_IDX (int)1e5

long long arr[MAX_IDX + 1];
long long n;

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        long long result = 0;
        scanf("%d", &n);
        for (long long i = 1; i <= n; ++i) {
            scanf("%lld", arr + i);
        }

        for (long long i = 1; i <= n; ++i) {
            long long a = arr[i];
            long long temp = (2 * i) % a;

            for (long long b = i - temp + a; b <= n; b += a) {
                result += (a * arr[b] == i + b);
            }
        }
        printf("%lld\n", result);
    }
    return 0;
}

C. Great Graphs

풀이 보기

풀이

음수 사이클을 만들지 않는 선에서 그래프가 가질 수 있는 cost 합의 최소를 찾는 문제이다.

우선 양수인 edge부터 생각해보자. cost의 최소가 되도록 해야하므로 양수인 edge는 가장 적게 사용하는 것이 좋다. 그 때의 edge의 합은 distance가 가장 큰 원소까지의 cost가 될 것이다. 예를 들어 배열이 $[0, 2, 4, 8, 11]$이라고 하면 아래의 양수 cost를 사용하는 것이 최소이다. 배열은 정렬하여 순서를 맞추고 edge를 추가해나가는 것이 좋다.

  • $0$ -> $2$까지의 cost $2$
  • $2$ -> $4$까지의 cost $2$
  • $4$ -> $8$까지의 cost $4$
  • $8$ -> $11$까지의 cost $3$
  • 위의 모든 cost의 합 = $11$ ( distance가 가장 큰 원소와 값이 같다 )

이제 가능한 모든 음수 edge를 추가하면 된다. 우선 양수 edge의 반대로 모든 edge에 같은 양의 음수 edge를 설치할 수 있다. 따라서 위의 양수 edge를 모두 상쇄하는 음수 edge를 그릴 수 있다. 고로 정답이 양수가 나오는 경우는 존재하지 않는다.

또한 각 원소들을 거미줄 형태로 그릴 때 edge를 추가할 수 있는지 검사한다. 규칙을 찾으면 알겠지만, 아래와 같은 규칙을 가지게 된다.

  • 1번 정점 ( 시작지점 ) 은 어떤 것과도 추가로 연결할 수 없다.
  • 2번 정점은 1번 정점과 연결할 수 있다. 물론 이것은 위에서 언급한 양수 edge 상쇄에 사용되므로 고려하지 않아도 된다.
  • 3번 정점은 1번 정점에 추가적으로 음수 edge를 그릴 수 있다. 이 때 사이클을 만들지 않는 수준에서 만들 수 있는 cost의 최댓값은 $a_3 - a_1$이다. ( 2번으로 연결하는 edge는 양수와의 edge의 상쇄에 사용한다. )
  • n번 정점은 1번 정점부터 n-2번 정점까지 추가적으로 음수 edge를 그릴 수 있다. 이 때의 추가로 제거 가능한 cost는 $\sum{a_n - a_i}$이다. 이것을 공식화하면 $(n-2) \times{a_n} - \sum_{i=1}^{n-2}{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
#include <stdio.h>

#define MAX_IDX (int)1e5

long long arr[MAX_IDX];
int n;

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

int cmp(long long* a, long long* b) {
    if (*a > *b) {
        return 1;
    }
    else if (*a == *b) {
        return 0;
    }
    else {
        return -1;
    }
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        long long ret = 0;
        scanf("%d", &n);

        for (int i = 0; i < n; ++i) {
            scanf("%lld", arr + i);
        }
        qsort(arr, n, sizeof(long long), cmp);

        long long sum = 0;
        for (int i = 2; i < n; ++i) {
            ret -= (arr[i] * (i - 1) - sum);
            sum += arr[i - 1];
        }
        printf("%lld\n", ret);
    }
    return 0;
}

결과

ContestStart timeRankSolvedRating changeNew rating
#728 (Div. 2)2021/6/26
00:35
9213+471628

C번 문제 이후로는 참가자 대부분이 문제를 풀지 못했다. contest 종료 때는 D번 문제를 푼 사람이 7명뿐이었고, E번 이후로는 푼 사람이 없을 정도로 문제가 오버밸런스였다. C번 문제까지 얼마나 빠르게 문제를 풀었느냐가 등수를 가른 요소가 되었다.

1600점을 돌파했다! Expert 단계에 진입했고, 파란색 닉네임을 획득했다. 유지하면서 버티는 것을 우선 목표로 잡아야겠다.

This post is licensed under CC BY 4.0 by the author.