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

test/aoj/challenge/2584.test.cpp

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

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

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

// Broken Cipher Generator の文法 (文字列を返す):
//   <Cipher> ::= <String> | <Cipher><String>          (暗黙の連接)
//   <String> ::= <Letter> | '['<Cipher>']'            ('[..]' は反転)
//   <Letter> ::= '+'<Letter> | '-'<Letter> | 'A'..'Z' ('+/-' は次/前の文字)
// '?' は A-Z のいずれか。復号後が辞書順最小になるよう ? を埋める (? は 3 個以下)。
using P = ExpressionParser<std::string>;

static std::string shift(std::string s, int d) {
    for (char &c : s) {
        int x = (c - 'A' + d) % 26;
        if (x < 0) x += 26;
        c = 'A' + x;
    }
    return s;
}

static P make_parser() {
    P p;
    p.prefix("+", [](const std::string &s) { return shift(s, 1); })
        .prefix("-", [](const std::string &s) { return shift(s, -1); })
        .concat(10, P::Assoc::Left, std::plus<std::string>(),
                [](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::isalpha(static_cast<unsigned char>(r[i])) || r[i] == '+' ||
                                            r[i] == '-' || r[i] == '[');
                })
        .atom([](P &q) -> std::string {
            if (q.consume("[")) {
                std::string in = q.parse_expression(0);
                if (!q.consume("]")) throw std::runtime_error("expected ']'");
                std::reverse(in.begin(), in.end());
                return in;
            }
            char c = q.peek();
            if (!std::isalpha(static_cast<unsigned char>(c))) throw std::runtime_error("expected letter");
            q.advance();
            return std::string(1, c);
        });
    return p;
}

int main() {
    P parser = make_parser();
    std::string line;
    while (std::getline(std::cin, line)) {
        if (line == ".") break;
        std::vector<int> qpos;
        for (int i = 0; i < (int)line.size(); ++i)
            if (line[i] == '?') qpos.push_back(i);
        int k = qpos.size();
        long long total = 1;
        for (int i = 0; i < k; ++i) total *= 26;
        std::string best;
        for (long long m = 0; m < total; ++m) {
            long long t = m;
            std::string cur = line;
            for (int i = 0; i < k; ++i) {
                cur[qpos[i]] = 'A' + t % 26;
                t /= 26;
            }
            std::string dec = parser.parse(cur);
            if (best.empty() || dec < best) best = dec;
        }
        std::cout << best << '\n';
    }
    return 0;
}