AtCoder ABC388 문제 풀이 분석

A - UPC 조합

문제 개요

입력 문자열의 첫 번째 글자 뒤에 "UPC"를 붙여 출력한다.

핵심 아이디어

문자열 인덱싱을 활용한 단순 구현.

구현

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    string str;
    cin >> str;
    cout << str.front() << "UPC" << '\n';
    
    return 0;
}

B - 무거운 뱀

문제 개요

n마리 뱀의 길이와 두께이 주어진다. 각 뱀의 무게는 길이×두께. 매일 모든 뱀의 길이가 1씩 증가할 때, D일 동안 매일 가장 무거운 뱀의 무게를 구한다.

핵심 아이디어

매일 길이를 증가시키고 전체 정렬하여 최댓값을 추출. O(D × n log n)으로 제약 내 해결 가능.

구현

#include <bits/stdc++.h>
using namespace std;

struct Snake {
    long long thick, len;
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n, days;
    cin >> n >> days;
    
    vector<Snake> snakes(n);
    for (auto& s : snakes) {
        cin >> s.thick >> s.len;
    }
    
    auto cmp = [](const Snake& x, const Snake& y) {
        return x.thick * x.len > y.thick * y.len;
    };
    
    for (int d = 1; d <= days; ++d) {
        for (auto& s : snakes) {
            s.len++;
        }
        sort(snakes.begin(), snakes.end(), cmp);
        cout << snakes[0].thick * snakes[0].len << '\n';
    }
    
    return 0;
}

C - 다양한 거울떡

문제 개요

오름차순으로 주어지는 n개의 떡 크기에서, 작은 떡을 큰 떡 위에 올릴 수 있다. 단, 아래 떡의 크기가 위 떡의 2배 이상이어야 한다. 만들 수 있는 떡 조합의 수를 구한다.

핵심 아이디어

각 떡을 아래쪽으로 사용할 때, 위에 올릴 수 있는 떡의 개수를 lower_bound로 빠르게 계산. 전체 복잡도 O(n log n).

구현

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n;
    cin >> n;
    
    vector<long long> rice(n);
    for (auto& x : rice) cin >> x;
    
    long long total = 0;
    for (int i = 0; i < n; ++i) {
        auto it = lower_bound(rice.begin(), rice.end(), rice[i] * 2);
        if (it != rice.end()) {
            total += rice.end() - it;
        }
    }
    
    cout << total << '\n';
    
    return 0;
}

D - 성인식

문제 개요

n명의 미성년자가 있고, i번째 사람은 ai개의 보석을 가지고 i년째에 성인이 된다. 성인이 될 때, 기존 성인들이 보석이 있다면 각각 1개쵸 나눠준다. n년 후 각자의 보석 개수를 출력한다.

핵심 아이디어

구간 업데이트와 점 쿼리가 필요하므로 세그먼트 트리 또는 펜윅 트리 활용. Lazy propagation으로 구간 덧셈 최적화.

구현

#include <bits/stdc++.h>
using namespace std;

struct Fenwick {
    vector<long long> bit;
    int n;
    
    Fenwick(int sz) : n(sz), bit(sz + 1) {}
    
    void add(int idx, long long val) {
        for (; idx <= n; idx += idx & -idx) bit[idx] += val;
    }
    
    void rangeAdd(int l, int r, long long val) {
        add(l, val);
        add(r + 1, -val);
    }
    
    long long query(int idx) {
        long long res = 0;
        for (; idx > 0; idx -= idx & -idx) res += bit[idx];
        return res;
    }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n;
    cin >> n;
    
    vector<long long> gems(n + 1);
    for (int i = 1; i <= n; ++i) cin >> gems[i];
    
    Fenwick fw(n);
    
    for (int i = 1; i <= n; ++i) {
        long long received = fw.query(i);
        long long available = gems[i] + received;
        long long give = min(available, (long long)(n - i));
        
        if (give > 0) {
            fw.rangeAdd(i + 1, min(i + (int)give, n), 1);
            gems[i] = available - give;
        } else {
            gems[i] = available;
        }
    }
    
    for (int i = 1; i <= n; ++i) {
        cout << gems[i] << " \n"[i == n];
    }
    
    return 0;
}

E - 동시 거울떡 최대화

문제 개요

C번과 유사하나, 동시에 만들 수 있는 거울떡 쌍의 최대 개수를 구한다.

핵심 아이디어

매개변수 탐색(Parametric Search). x개의 쌍을 만들 수 있는지 판정하는 check 함수를 설계. 작은 떡들끼리, 큰 떡들끼리 매칭하는 그리edy한 전략이 최적.

구현

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n;
    cin >> n;
    
    vector<long long> mochi(n);
    for (auto& x : mochi) cin >> x;
    
    auto feasible = [&](int pairs) -> bool {
        for (int i = 0; i < pairs; ++i) {
            if (mochi[i] * 2 > mochi[n - pairs + i]) {
                return false;
            }
        }
        return true;
    };
    
    int low = 0, high = n / 2, best = 0;
    while (low <= high) {
        int mid = (low + high) / 2;
        if (feasible(mid)) {
            best = mid;
            low = mid + 1;
        } else {
            high = mid - 1;
        }
    }
    
    cout << best << '\n';
    
    return 0;
}

문제 출처: AtCoder Beginner Contest 388

태그: AtCoder C++ 알고리즘 매개변수탐색 세그먼트트리

5월 22일 22:43에 게시됨