algo — C++23 日本語リファレンス GitHub

test/aoj/challenge/2857.test.cpp

AC · 最終更新 2026-09-06 · GitHub

問題: https://onlinejudge.u-aizu.ac.jp/problems/2857

依存するヘッダ(1)
実装
// competitive-verifier: PROBLEM https://onlinejudge.u-aizu.ac.jp/problems/2857
#include <array>
#include <iostream>
#include <map>
#include <string>
#include "parser/parser.hpp"

// Tournament Chart: トーナメント表 (BNF: winner ::= person | "[" winner "-" winner "]")
// を parse し、各人の勝利数申告が矛盾なく実現可能か判定する。
// 部分木を評価すると「その部分木の優勝者になれる人 → 部分木内での勝利数」の
// マップが得られる (負けた人の申告は途中で確定・検証済み)。group '[' ']' と
// 二項 '-' で木を組み立てる ExpressionParser の例。
using Map = std::map<char, int>;  // 優勝者候補 → 部分木内で勝った回数
using P = ExpressionParser<Map>;

int main() {
    std::array<int, 26> v{};  // 各人の申告勝利数
    std::string s;
    std::getline(std::cin, s);
    char ch;
    int val;
    while (std::cin >> ch >> val) v[ch - 'a'] = val;

    P p;
    p.group('[', ']')
        .binary("-", 10, P::Assoc::Left,
                [&v](const Map &L, const Map &R) -> Map {
                    // 一方が「きれいに敗退できる」= 優勝者候補の申告が部分木勝利数と一致
                    auto can_lose = [&](const Map &m) {
                        for (auto &[c, w] : m)
                            if (v[c - 'a'] == w) return true;
                        return false;
                    };
                    Map res;
                    if (can_lose(R))  // R が敗退 → L 側の候補が 1 勝上乗せして勝ち上がる
                        for (auto &[c, w] : L) res[c] = w + 1;
                    if (can_lose(L))
                        for (auto &[c, w] : R) res[c] = w + 1;
                    return res;
                })
        .atom([](P &q) -> Map {
            char c = q.peek();
            q.advance();
            return {{c, 0}};
        });

    Map root = p.parse(s);
    bool ok = false;
    for (auto &[c, w] : root)  // 優勝者の申告が全勝利数と一致すれば実現可能
        if (v[c - 'a'] == w) ok = true;
    std::cout << (ok ? "Yes" : "No") << '\n';
    return 0;
}