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

test/aoj/challenge/1244.test.cpp

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

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

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

// 分子式の重さ: 原子記号 (大文字 or 大文字+小文字) の並びで、単位 (原子 or
// '(' 式 ')') の直後に乗数 (2..99) を後置できる。連接は重さの和。
// 未知の原子記号があれば UNKNOWN。括弧は atom 側で扱うため no_group()。
using ll = long long;
std::map<std::string, ll> weight;
using P = ExpressionParser<ll>;

int main() {
    std::string a;
    ll w;
    while (std::cin >> a) {
        if (a == "END_OF_FIRST_PART") break;
        std::cin >> w;
        weight[a] = w;
    }
    std::string line;
    while (std::cin >> line) {
        if (line == "0") break;
        P p;
        p.no_group()
            .concat(10, P::Assoc::Left, std::plus<ll>(),
                    [](std::string_view r) {
                        std::size_t i = 0;
                        while (i < r.size() && std::isspace(static_cast<unsigned char>(r[i]))) ++i;
                        return i < r.size() && (std::isupper(static_cast<unsigned char>(r[i])) || r[i] == '(');
                    })
            .atom([](P &q) -> ll {
                // 番兵 '\0' により末尾でも cur() が安全に返るので size チェック不要。
                ll base;
                if (q.consume("(")) {
                    base = q.parse_expression(0);
                    if (!q.consume(")")) throw std::runtime_error("expected ')'");
                } else {
                    if (!std::isupper(static_cast<unsigned char>(q.cur()))) throw std::runtime_error("expected atom");
                    std::string sym(1, q.cur());
                    q.advance();
                    if (std::islower(static_cast<unsigned char>(q.cur()))) sym += q.cur(), q.advance();
                    auto it = weight.find(sym);
                    if (it == weight.end()) throw std::runtime_error("unknown atom");
                    base = it->second;
                }
                ll m = 0;
                bool has_mult = false;
                while (std::isdigit(static_cast<unsigned char>(q.cur()))) {
                    m = m * 10 + (q.cur() - '0');
                    q.advance();
                    has_mult = true;
                }
                if (has_mult) base *= m;
                return base;
            });
        try {
            std::cout << p.parse(line) << '\n';
        } catch (...) { std::cout << "UNKNOWN\n"; }
    }
    return 0;
}