ABC 240

A - Edge Checker

問題

$|a-b| = 1$ または $a = 1, b = 10$ のときは Yes, それ以外のときは No

提出コード

B - Count Distinct Integers

問題

$N$ 個の要素全部 set に突っ込んで最後に size を出力

提出コード

C - Jumping Takahashi

問題

$dp[i][x]$ を $i$ 回目のジャンプで座標 $x$ に行けるかとし 初期値 $dp[0][0] = true$ とする.

$dp[i-1][x] = true$ ならば $dp[i][x+a] = dp[i][x+b] = true$ に更新する.

提出コード

D - Strange Balls

問題

筒の中に入っているボールの数を同じ数字が書かれたボールに関しては圧縮してもつ.

筒の中に [2, 3, 3, 2, 4, 4, 4, 5] と入っていたら [{2, 1}, {3, 2}, {2, 1}, {4, 3}, {5, 1}] という風に {数字, 個数} として保持する.

新たなボールを加えるときは最後尾のペアを見て数字が同じだったら個数を増やす, 違ったらペアを増やすとしていく. 個数を増やした結果数字と個数が一緒になったらそのペアは配列から削除する.

提出コード

E - Ranges on Tree

問題

入れ子集合モデルを知っていると比較的簡単に実装方針が立ったのではないかと思う.

ref 第5回 SQLで木構造を扱う~入れ子集合モデル (1)入れ子集合モデルとは何か

まず葉の数字は $L_i = R_i$ とするのが最適. そうでなければ無駄に $\max \{L_i, R_i\}$ の値が大きくなってしまう.

また

より, 全ての葉は違う数字を振るのが最適である. 葉以外のノードでは $L_i = \min{\text{全ての子ノードの } L}$, $R_i = \max{\text{全ての子ノードの } R}$ というのを 葉の方から決めていけば良い.

ここで, 葉に振る数字は DFS での訪れた順に数字を振らなければならない. 葉への数字の振り方がいい加減だと WA になる.

例えば下図のようなときに, 葉ノード 4, 5, 6, 7 に数字を1から連番で振ると図の ようになるが, これでは $S_2 \cap S_3 = \empty$ なのに $[1, 3] \cap [2, 4] \neq \empty$ になってしまう. そのため, 葉への数字の割り振りは DFS で訪れた順でないといけない. e.png

int n;
vvint graph;
// P: L, R
vector<P> ans;
int num = 1;

void dfs(int x, int p) {
    // leaf
    if (x != 0 && graph[x].size() == 1) {
        ans[x] = {num, num};
        num++;
        return;
    }

    ll mn = INF, mx = -INF;
    for (int nx : graph[x]) {
        if (nx == p)
            continue;
        dfs(nx, x);
        chmin(mn, ans[nx].first);
        chmax(mx, ans[nx].second);
    }
    ans[x] = {mn, mx};
}

void solve() {
    cin >> n;
    graph.resize(n);
    ans.resize(n, {INF, -INF});

    rep(i, n - 1) {
        int u, v;
        cin >> u >> v;
        u--, v--;
        graph[u].push_back(v);
        graph[v].push_back(u);
    }

    dfs(0, -1);

    for (auto [l, r] : ans) {
        cout << l << ' ' << r << endl;
    }
}

提出コード