본문 바로가기
Problem Solving/Baekjoon Online Judge

제1회 블롭컵

by 사향낭 2022. 3. 1.

 

문제 난이도 분포가 다양하여 생각보다는 많은 문제인 6솔을 했다.

 

컴퓨터 업데이트가 자동적으로 되어 날아갔다.... 다시 써본다...

 

 

 

Editorial

 

 

제1회 블롭컵 해설

제1회 블롭컵 해설

docs.google.com

 

 

A. blobnom

 

 

24498번: blobnom

블롭들은 심심해서 서로를 이용해 $N$개의 탑을 만들었다. 각 탑의 높이는 그 탑에 있는 블롭의 수와 같다. 여러분은 다음 행동을 $0$회 이상 할 수 있다. 처음과 마지막이 아닌 탑 중 하나를 선

www.acmicpc.net

 

각각의 높이가 주어진 N개의 탑이 있다.

 

i번째 탑에 대해, i + 1번째 탑과 i - 1번째 탑의 높이를 1씩 줄이고, i번째 탑의 높이를 1 높이는 operation이 있다.

 

(첫 번째 탑과 마지막 탑을 i번째로 고를 수는 없다.)

 

operation을 0번 이상하여 탑의 최대 높이를 구하여라.

 

 

\( max \) \( h_i + min(h_{i - 1}, h_{i + 1}) \) 을 구하면 된다.

 

첫 번째와 마지막 탑의 경우 min 부분 없이 고려한다.

 

 

 

B. blobyum

 

 

24499번: blobyum

4번 애플파이와 1번 애플파이를 먹으면 총 맛의 합이 9이고, 이가 최댓값이다.

www.acmicpc.net

 

N개의 애플파이가 원 모양으로 배치되어 있다.

 

각각 애플파이의 맛있는 정도가 주어진다.

 

연속된 K개를 먹는다고 하였을 때 맛있는 정도의 합의 최댓값을 구하여라.

 

 

애플파이가 원형으로 배치되어 있기 때문에 N개 애플파이를 2N - 1개로 확장시켜 생각한다.

 

\( a_i = a_{i - N} \) for \( N + 1 \leq i \leq 2N \)

 

그리고 누적값을 계산한다.

 

그리고 배열을 순회하며 K개만큼의 합의 최댓값을 구하면 된다.

 

 

 

C. blobblush

 

 

24500번: blobblush

길이 K의 수열 A가 같은 길이의 수열 B보다 사전순으로 앞선다는 것은, A의 1~(i-1)번째 원소와 B의 1~(i-1)번째 원소가 같으면서, A의 i번째 원소가 B의 i번째 원소보다 작은 i가 있다는 것이다.

www.acmicpc.net

 

1부터 \( N \) 까지의 양의 정수가 적힌 숫자 카드가 있다.

 

다음과 같은 조건으로 카드를 뽑을 때, 뽑는 카드의 수와 적힌 각 수를 구하여라.

  • 뽑은 카드들에 적힌 수를 모두 ⊕한 값이 최대가 되어야 한다. ⊕는 배타적 논리합(xor)을 의미한다.
  • 첫 번째 조건에 맞게 카드를 뽑는 방법이 여러 가지인 경우, 카드를 최대한 적게 뽑아야 한다.
  • 두 번째 조건에 맞게 카드를 뽑는 방법이 여러 가지인 경우, 사전 순으로 가장 앞서도록 뽑아야 한다.

 

 

\( N \) 을 이진수로 표현하였을 때의 길이를 n이라고 하였을 때, 1부터 \( N \)까지의 카드를 뽑아 xor하여 만들 수 있는 최댓값은 \( 2^n - 1 \)이다.

 

따라서 \( N \)이 \( 2^n - 1 \)이라면 \( N \)만 뽑으면 된다.

 

그렇지 않다면, 조건에 부합하도록 \( 2^n - 1 - N \)과 \( N \)을 뽑으면 된다.

 

 

 

D. blobaww

 

 

24501번: blobaww

주환이가 조건에 맞게 고를 수 있는 경우의 수를 $10^9+7$로 나눈 나머지를 출력한다.

www.acmicpc.net

 

문자 E, S, M으로 구성된 N x M 2차원 행렬이 있다. (그 행렬을 \( ESM \) 이라고 하자)

 

\( ESM_{x_1, y_1} = E \), \( ESM_{x_2, y_2} = S \), \( ESM_{x_3, y_3} = M \) ( \( 1 \leq x_1 \leq x_2 \leq x_3 \leq N \), \( 1 \leq y_1 \leq y_2 \leq y_3 \leq M \) ) 을 만족하는 \( (x_1, y_1) \), \( (x_2, y_2) \), \( (x_3, y_3) \) 의 쌍의 개수를 구하여라.

 

 

2차원 누적값을 구하는 것을 3번 반복하면 된다.

 

처음에는 E의 개수를 누적하여 2차원 배열으로 만든다.

 

\( E_{x, y} \) = \( \| \{ (x_1, y_1) | ESM_{x_1, y_1} = E, 1 \leq x_1 \leq x, 1 \leq y_1 \leq y \} \| \)

 

그런다음 위 배열을 이용하여 다음을 만족하는 \( (x_1, y_1) \), \( (x_2, y_2) \) 쌍의 개수를 누적하여 2차원 배열으로 만든다.

 

\( S_{x, y} \) = \( \| \{ ( (x_1, y_1), (x_2, y_2) ) | ESM_{x_1, y_1} = E, ESM_{x_2, y_2} = S, 1 \leq x_1 \leq x_2 \leq x, 1 \leq y_1 \leq y_2 \leq y \} \| \)

 

그런다음 위 배열을 이용하여 \( (x_1, y_1) \), \( (x_2, y_2) \), \( (x_3, y_3) \) 쌍의 개수를 구해준다.

 

 

 

E. blobsad

 

 

24502번: blobsad

채완이와 주환이가 이 일을 마칠 수 있는 최소 시간을 초 단위로 출력한다. 만약, 마칠 수 없다면 blobsad를 출력한다.

www.acmicpc.net

 

1 x 1 정사각형 \( N \)개로 나누어진 1 x \( N \) 크기의 직사각형 통 안에 블롭을 키우고 있다.

 

i번째 1 x 1 정사각형에는 블롭 \( a_i \)마리를 키운다.

 

1초마다 하나의 블롭을 인접한 칸으로 옮길 수 있다.

 

각 칸에 있는 블롭의 수가 \( K \)의 배수가 아니면 블롭이 슬퍼한다.

 

블롭이 슬퍼하지 않게 블롭을 옮기는 일을 마칠 수 있는 최소 시간을 구하여라.

 

 

그리디로 해결되는 문제이다.

 

왼쪽부터 오른쪽으로 순회하며 블롭의 수의 합이 K 이상이 되는 구간 (i, j)를 찾는다.

 

결국 구간 (i, j) 사이의 한 칸에 블롭을 K마리 몰아야 할것이다.

 

이를 그리디하게 계산해준다.

 

다시 구간 (i, j)에서 왼쪽부터 오른쪽으로 순회하며 i번째 칸에 K 마리 블롭을 옮겼을 때와 i + 1번째 칸에 K 마리 블롭을 옮겼을 때의 시간을 구하여 시간이 덜 걸리는 방향으로 블롭들을 옮겨서 처리한다.

 

변수명이 더럽긴 한데 코드는 아래와 같다.

 

#include <bits/stdc++.h>

using namespace std;

long long n, k;
long long cnt[1000000];

int main() {
    // freopen("input.txt", "r", stdin);
    scanf("%lld %lld", &n, &k);

    long long acc = 0;
    for (int i = 0; i < n; i++) {
        scanf("%lld", &cnt[i]);
        cnt[i] %= k;
        acc += cnt[i];
    }

    if (acc % k) {
        printf("blobsad");
    } else {
        long long ret = 0;

        for (int cur = 0; cur < n;) {
            if (cnt[cur]) {
                int right = cur + 1;
                long long rest_cnt = k - cnt[cur];
                long long sofar_cnt = 0, cost = 0;

                while (sofar_cnt < rest_cnt) {
                    sofar_cnt += cnt[right];
                    cost += (cnt[right] * (right - cur));
                    right++;
                }

                long long unn_cnt = 0;
                if (sofar_cnt > rest_cnt) {
                    unn_cnt = sofar_cnt - rest_cnt;
                    cost -= (unn_cnt * (right - cur - 1));
                }

                long long move_cost = cnt[cur];
                while (2 * move_cost < k) {
                    cur++;
                    ret += move_cost;
                    cost -= (k - move_cost);
                    move_cost += cnt[cur];
                }

                ret += cost;
                cnt[right - 1] = unn_cnt;
                cur = right - 1;
            } else {
                cur++;
            }
        }
        printf("%lld", ret);
    }
}

 

 

 

F. blobfearful

 

 

24503번: blobfearful

$1$일에 블롭이 $1$마리 있을 경우, $3$일째 되는 날이면 블롭의 수는 $1 \times 2 \times 3=6$으로 처음으로 $K$의 배수가 된다.

www.acmicpc.net

 

i일에는 블롭의 수가 전날의 i배만큼 늘어난다.

 

1일에는 블롭이 \(a_i\)마리가 있다.

 

블롭의 수가 K의 배수가 아니면 블롭들이 불안해 한다.

 

처음으로 블롭들이 불안해 하지 않는 날을 구하여라.

 

 

충분히 풀수 있는 문제인데 시간복잡도 계산을 잘못했다.

 

결국 답이 D라면 \( a_i * \) D!가 K로 나누어질 것이다.

 

그말은 즉은 K의 소인수 중 하나인 \( p \)에 대해 \( a_i * \) D!를 p로 소인수분해한 값 \( p_D \)와 K를 소인수분해 한 값 \( p_K \)의 관계가 \( p_D \geq p_K \) 을 만족해야 한다는 것이다.

 

K의 소인수 \( p \)와 제시된 \( a_ i \)을 \( p \)로 소인수분해한 값 \( p_a \)에 대하여 \( p_a \geq p_K \)라면 넘기고 \( p_a < p_K \)라면 D!를 \( p \)로 소인수분해 했을 때의 인수가 \( p_K - p_a \)개 이상인 최솟값 D를 찾는다.

 

모든 \( p \)에 대하여 구한 D의 최댓값이 정답이 된다.

 

최적화는 더 할수 있을건데 D를 찾는 로직을 이상하게 짜서 시간낭비가 너무 심했어서 스킵.

 

#include <bits/stdc++.h>

using namespace std;

long long k;
vector<long long> p, factor;

void set_p(long long tmp_k) {
    int end_idx = sqrt(tmp_k);
    for (int i = 2; i <= end_idx && (tmp_k != 1); i++) {
        if (!(tmp_k % i)) {
            p.push_back(i);
            factor.push_back(0);

            while (!(tmp_k % i)) {
                tmp_k /= i;
                factor.back()++;
            }
        }
    }

    if (tmp_k != 1) {
        p.push_back(tmp_k);
        factor.push_back(1);
    }
}

long long get_factor(long long target, long long p_i) {
    long long ret = 0;
    while (!(target % p_i)) {
        ret++;
        target /= p_i;
    }

    return ret;
}

long long get_cnt(long long cur, long long div) {
    long long cnt = 0;
    long long cur_div = div;

    while (cur_div <= cur) {
        cnt += (cur / cur_div);
        cur_div *= div;
    }

    return cnt;
}

int main() {
    // freopen("input.txt", "r", stdin);

    int q;
    scanf("%lld %d", &k, &q);

    set_p(k);

    int factor_size = p.size();
    while (q--) {
        long long a;
        scanf("%lld", &a);

        long long ret = 1;

        for (int i = 0; i < factor_size; i++) {
            long long cur_factor = get_factor(a, p[i]);

            if (cur_factor < factor[i]) {
                long long cnt = factor[i] - cur_factor;

                long long left = 2, right = cnt * p[i];
                long long target = right;

                while (left <= right) {
                    long long mid = (left + right) / 2;

                    if (get_cnt(mid, p[i]) >= cnt) {
                        target = mid;
                        right = mid - 1;
                    } else {
                        left = mid + 1;
                    }
                }

                if (target > ret) {
                    ret = target;
                }
            }
        }
        printf("%lld ", ret);
    }

    return 0;
}

 

 

 

G. blobcry

 

 

24504번: blobcry

첫째 줄에 Light 왕국의 섬의 개수 $N$과 다리의 개수 $M$이 주어진다. 둘째 줄부터 $M$개의 줄에 걸쳐 $i$번 다리가 연결하는 두 섬의 번호 $u_i$, $v_i$가 공백으로 구분되어 주어진다.

www.acmicpc.net

 

단절선을 지웠을 때 component의 vertex 개수를 구하는 것을 공부한 다음 풀 예정.

 

 

 

H. blobyperthink

 

 

24505번: blobhyperthink

첫째 줄에 조건에 맞는 쌍의 개수를 $10^9+7$로 나눈 나머지를 출력한다.

www.acmicpc.net

 

길이가 N인 수열 A가 있다.

 

다음 조건을 만족하는 \( (i, j, k, l, m, o, p, q, r, s, t) \) 쌍의 개수를 \( 10^9 + 7 \) 로 나눈 나머지를 구하여라.

 

  • \(  i < j < k < l < m < o < p < q < r < s < t  \) 이고, \( A_i < A_j < A_k < A_l < A_m < A_o < A_p < A_q < A_r < A_s < A_t \) 이다.

 

D번 blobaww처럼 하나씩 하나씩 조건을 늘려나가면서 풀면 된다.

 

처음에는 \( (i, j) \) 쌍의 개수를, 그 다음에는 \( (i, j, k) \) 의 쌍의 개수를 구하면서 변수를 하나씩 추가시켜준다.

 

11중 segment tree를 사용하여 풀었다.

 

 

다이아는 나중에~

'Problem Solving > Baekjoon Online Judge' 카테고리의 다른 글

#2749 피보나치 수  (0) 2022.01.10
#2933 미네랄  (0) 2022.01.08
#15683 감시  (0) 2022.01.06
#14809 경사로  (0) 2022.01.05
#14503 로봇 청소기  (0) 2022.01.04

댓글