본문 바로가기
BOJ

BOJ 12963

by gmroh 2025. 2. 6.

문제의 핵심 관찰은 3^n보다 작은 3의 제곱수들을 아무리 더해도 3^n을 넘을 수 없다는 것이다. 즉, 시작점에서 끝점으로 가는 경로에서 가장 작은 용량을 갖는 간선만 파악한다면 나머지 간선들은 신경쓸 필요가 없다. 그래프의 간선의 가중치가 이런식으로 제곱수의 형태를 갖는 경우, 대개 a^0 + ... + a^n - 1 < a^n인 특성을 이용하는 문제가 많은 것 같다.

 

입력된 간선들을 역순으로 뒤집고 3의 제곱수들의 나머지를 미리 계산해 놓은 다음, Union Find로 0과 n - 1이 합쳐지는 순간 가장 작은 용량을 정답에 더하면 된다. 이때, 합쳐지는 순간 가장 작은 용량을 갖는 간선은 포화상태가 되기 때문에 없는 것과 마찬가지이다. Union을 수행하기 이전의 배열을 저장해 두었다가 0과 n - 1이 합쳐졌다면 정답에 값만 더해 주고 배열은 원래대로 되돌리면 된다.

 

#include <bits/stdc++.h>

using namespace std;
using ll = long long;
using pll = pair<ll, ll>;

constexpr ll MOD = 1e9 + 7;

inline void init() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
}

vector<ll> p;

ll find(ll x) {
    return x == p[x] ? x : p[x] = find(p[x]);
}

int main() {
    init();

    ll n, m;

    cin >> n >> m;

    vector<pll> edges(m);
    vector<ll> sz(1, 1LL);
    p.resize(n);

    for (auto& [u, v] : edges) {
        cin >> u >> v;
        sz.emplace_back(sz.back() * 3 % MOD);
    }

    iota(p.begin(), p.end(), 0LL);
    ll ans = 0;

    for (ll i = m - 1; i >= 0; i--) {
        auto [u, v] = edges[i];
        u = find(u), v = find(v);

        if (u != v) {
            auto tmp = p;
            p[u] = v;

            if (find(0) == find(n - 1)) {
                ans = (ans + sz[i]) % MOD;
                p = tmp;
            }
        }
    }

    cout << ans;

    return 0;
}

'BOJ' 카테고리의 다른 글

BOJ 33601  (0) 2025.05.03
BOJ 17533  (0) 2025.05.03
BOJ 25055  (0) 2025.02.14
BOJ 16615  (0) 2025.02.13
BOJ 24272  (0) 2025.02.06