728x90

결과

내가 실제로 참여한 8번째 CF 대회이다$.$ Div2 대회에서는 4솔 이상을 한 적도 없고 그 정도 실력이 안된다고 생각했었는데, 이번 Round에서 4솔을 했다..!

image

이전 7개 대회의 성적

 

이번 대회의 성적이 좋았던 이유는 물론 D번을 푼 것도 있겠지만, B, C번을 (특히 B번을) 빠르게 풀었다.
만약 B, C번에서 10분정도 더 썼더라면 D번을 풀 수 없었을 것이다.

 

Dashboard - Educational Codeforces Round 107 (Rated for Div. 2) - Codeforces

 

codeforces.com

A. Review Site

처음에 지문을 제대로 읽지 않아 서버가 2개라는 사실을 모르고 문제를 풀어 틀렸다.

서버가 2개이므로 숫자가 1, 3일 때 무조건 +1을 하면 된다.


B. GCD Length

세 정수를 입력받는데, 각각 $a = x$의 길이, $b = y$의 길이, $c = gcd(x, y)$의 길이이다.

먼저, $x = 10^{a-1}$, $y = 10^{b-1}$로 맞춰놓으면, $gcd(10^{a-1}, 10^{b-1}) = 10^{min(a-1, b-1)}$ 가 성립한다.

여기서 $c \leq min(a, b)$ 이므로, $y$ 에 $10^{c-1}$ 를 더하면, 즉
$x = 10^{a-1}$, $y = 10^{b-1}+10^{c-1}$ 로 맞추면 $gcd(x, y) = 10^{c-1}$ 이므로 항상 성립한다.


C. Yet Another Card Deck

array의 크기는 $n = 3\times10^5$, query의 개수는 $q = 3\times10^5$ 이므로 naive하게 구현하면 $O(nq)$가 되어 시간 초과가 발생한다.

색깔의 개수가 $50$ 이하라는 점을 이용해 각 색깔에서 가장 앞에 있는 카드의 위치만 저장해도 된다는 점을 깨달았다.

그리고 각 쿼리가 진행될 때 $50$개의 위치를 바꾼다. 쿼리에 해당하는 색깔의 위치를 1로 바꾸고, 앞으로 이동하기 전 카드의 위치보다 앞에 있는 위치들을 모두 1 더해준다.

이 때 시간복잡도는 $O(50q)$이므로 충분히 통과된다.


D. Min Cost String

$cost$의 정의는 길이가 $n$인 문자열에서 길이가 2인 연속된 부분 문자열 2개를 잡았을 때 같은 것들의 개수이다. 입력은 문자열 길이 $n$, 사용할 수 있는 알파벳 개수 $k$이다.

$n$일 때 길이가 2인 연속된 부분 문자열의 개수는 $n-1$개이다. $k$개의 알파벳을 사용할 때 만들 수 있는 길이가 2인 문자열의 개수는 $k^2$개이다.

즉, $n-1 \leq k^2$이라면 $cost = 0$ 이 되는 문자열을 만들 수 있다.

소스코드 보기
#include <bits/stdc++.h>
using namespace std;

int main() {
    ios_base :: sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    int n, k;
    cin >> n >> k;
    int have[k][k];
    for (int i = 0; i < k; i++) {
        for (int j = 0; j < k; j++) have[i][j]=0;
    }
    string a; a.push_back('a');
    int cycle = k*k;

    while (a.length() != n) {
        int first = a.back()-'a';
        int tag = 0;
        for (int j = 0; j < k; j++) {
            if (have[first][j] == (a.length()-1)/cycle) {
                a.push_back(j+'a');
                have[first][j]++;
                tag = 1;
                break;
            }
        }
        if (tag == 0) {
            a.pop_back();
            int r = a.back()-'a';
            have[r][first]--;
            a.push_back(first+'a'+1);
            have[r][first+1]++;
        }
    }
    cout << a;
}

 

코드 설명
$have[m][n]$: 첫 번째 문자가 $'a'+m$이고, 두 번째 문자가 $'a'+n$인 문자열의 개수를 저장하는 배열이다.
만약 $have[m][n]$가 $p \geq 2$이면 $cost$에 $ {}_{p}{C}_2 $가 더해진다.
즉, 모든 $have[m][n]$가 골고루 분포되는 것이 $cost$를 최소화시키는 방법이다.
예를 들어, $n = ak^2+1$일 때, 모든 $have[m][n]$를 $a$로 만들어야 $cost$가 최소이다.
이런 문자열이 만들어지게끔 백트래킹(?) 비슷한 방식으로 탐색하면 된다.

이 때 시간복잡도는 $O(nk^2)$이다.

728x90

'CF&AC&Open' 카테고리의 다른 글

SUAPC 2023 Summer Open 후기  (3) 2023.09.04
[Codeforces Round #714] A, B, C번 풀이  (0) 2022.06.20

+ Recent posts