Determine Winning Islands in Race

Codeforces Round 965 (Div. 2) D

1 min readPSCodeforces

동아리 선배에게 문제를 하나 추천 받아서 풀이를 써 보았습니다.

문제

링크: Determine Winning Islands in Race

난이도: 2100

풀이

Elsie가 Bessie를 이기기 위해서는 u<su < s인 간선 (u,v)(u, v)를 이용해서 Bessie를 뛰어넘어야 합니다.

11에서 시작해서 ii까지 Elsie가 도착하는 데 필요한 최소 이동 횟수(=간선 개수)를 did_i라 합시다.

u<su < s인 간선 (u,v)(u, v)를 사용해서 vv에 도착한다면 Elsie가 vv까지 가는데 필요한 이동 횟수는 du+1d_u + 1입니다.

만약 dv+1=dv+1d_{v + 1} = d_v + 1이라면 vv에서 Bessie를 뛰어넘지 못하는 경우 v+1v + 1에서도 뛰어넘지 못할 것입니다. 마찬가지로 dv+i=dv+id_{v + i} = d_v + i라면 vv와 v+iv + i에서 Bessie를 뛰어넘을 수 있는지 여부는 동일합니다.

따라서 중요한 것은 v−dvv - d_v의 값으로, 이 값이 제일 큰 정점 vv만 확인해도 Bessie를 뛰어넘을 수 있는지 판단할 수 있습니다.

이 값이 가장 큰 vv에 대해 생각해 봅시다. Bessie는 vv에 도달하기 위해 v−sv - s만큼의 이동이 필요합니다.

따라서 v−s≤dvv - s \leq d_v가 Bessie가 이길 필요충분조건이 됩니다.

이때 dv=v−(v−dv)d_v = v - (v - d_v)이므로 위 부등식에 대입해서 식을 정리하면 s≥v−dvs \geq v - d_v가 됩니다.

위 알고리즘을 naive하게 구현하면 O(n2)O(n^2)이므로 시간 초과를 받습니다.

did_i는 DP를 이용해서 총 O(n+m)O(n + m)에 갱신하고, v−dvv - d_v의 최댓값은 각 ss에 대해 판단이 끝날 때 마다 ss에서 nn 방향으로 가는 간선을 모두 검사해주면 전체 알고리즘에서 O(m)O(m)에 갱신할 수 있습니다.

코드

#include <bits/stdc++.h>
using namespace std;
 
template <typename T>
bool minimize(T& target, T candidate) {
    return target > candidate ? (target = candidate, true) : false;
}
template <typename T>
bool maximize(T& target, T candidate) {
    return target < candidate ? (target = candidate, true) : false;
}
 
void solve() {
    int n, m;
    cin >> n >> m;
 
    vector<vector<int>> alts(n + 1);
    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v;
 
        if (u > v) swap(u, v);
 
        alts[u].push_back(v);
    }
 
    vector<int> d(n + 1, n + 1);
    d[1] = 0;
    int winBound = 0; // max(v - dist[v])
    for (int s = 1; s < n; s++) {
        cout << (winBound <= s);
 
        minimize(d[s], d[s - 1] + 1);
        for (int v : alts[s]) {
            minimize(d[v], d[s] + 1);
            maximize(winBound, v - d[v]);
        }
    }
    cout << '\n';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
 
    int t;
    cin >> t;
 
    while (t--) solve();
 
    return 0;
}

댓글

이름과 이메일을 입력해 댓글을 남겨주세요.