1 条题解

  • 0
    @ 2026-10-27 13:20:33

    思路与算法

    先检查唯一末尾@,再按语法把中缀转换为后缀Token,识别多位整数、一元负号与括号。出现未知字符、缺操作数、相邻操作数、括号不匹配或非法运算符时输出NO。转换成功后必须用值栈计算后缀;除0或超域也输出NO,否则输出精确值。

    正确性说明

    语法层依次处理正确优先级,只有完整消费输入且每个产生式都完成才生成合法后缀,因此不会接受残留字符或缺项。后缀栈归纳保证合法输入的值正确;检查每次出栈所需数量、除数和数值域,保证非法运算不会被当成普通值。该实现实际先存后缀再栈求值,不以直接递归求值替代题意。

    复杂度

    输入与Token初始化O(L),解析O(L),栈计算O(L),空间O(L),含递归与后缀和值栈。所有数值域核验在整数中执行。

    易错点

    @只作为结束标记,不能出现在算式中间。本地不支持一元正号,所以1++2非法,但1--2按减去负数为3。此题不允许^。空括号、除0、超过中间值域均输出大写NO。

    参考代码(C++11)

    #include <bits/stdc++.h>
    using namespace std;
    using ll = long long;
    struct Token {
        char op;
        ll value;
    };
    struct Parser {
        string s;
        size_t at = 0;
        bool powers;
        vector<Token> post;
        Parser(string text, bool allow) : s(text), powers(allow) {
        }
        void spaces() {
            while (at < s.size() && isspace((unsigned char)s[at]))
                ++at;
        }
        bool take(char c) {
            spaces();
            if (at < s.size() && s[at] == c) {
                ++at;
                return true;
            }
            return false;
        }
        void atom() {
            spaces();
            if (take('(')) {
                expr();
                if (!take(')'))
                    throw 1;
                return;
            }
            if (at >= s.size() || !isdigit((unsigned char)s[at]))
                throw 1;
            ll x = 0;
            while (at < s.size() && isdigit((unsigned char)s[at])) {
                x = x * 10 + s[at++] - '0';
                if (x > 1000000000LL)
                    throw 1;
            }
            post.push_back({'n', x});
        }
        void power() {
            atom();
            if (take('^')) {
                if (!powers)
                    throw 1;
                unary();
                post.push_back({'^', 0});
            }
        }
        void unary() {
            if (take('-')) {
                unary();
                post.push_back({'~', 0});
            } else
                power();
        }
        void term() {
            unary();
            while (true) {
                if (take('*')) {
                    unary();
                    post.push_back({'*', 0});
                } else if (take('/')) {
                    unary();
                    post.push_back({'/', 0});
                } else
                    break;
            }
        }
        void expr() {
            term();
            while (true) {
                if (take('+')) {
                    term();
                    post.push_back({'+', 0});
                } else if (take('-')) {
                    term();
                    post.push_back({'-', 0});
                } else
                    break;
            }
        }
        ll run() {
            expr();
            spaces();
            if (at != s.size())
                throw 1;
            vector<ll> stack;
            auto checked = [](__int128 v) {
                if (v > 1000000000000LL || v < -1000000000000LL)
                    throw 1;
                return (ll)v;
            };
            for (auto t : post) {
                if (t.op == 'n') {
                    stack.push_back(t.value);
                    continue;
                }
                if (t.op == '~') {
                    if (stack.empty())
                        throw 1;
                    stack.back() = -stack.back();
                    continue;
                }
                if (stack.size() < 2)
                    throw 1;
                ll b = stack.back();
                stack.pop_back();
                ll a = stack.back();
                stack.pop_back();
                ll v = 0;
                if (t.op == '+')
                    v = checked((__int128)a + b);
                else if (t.op == '-')
                    v = checked((__int128)a - b);
                else if (t.op == '*')
                    v = checked((__int128)a * b);
                else if (t.op == '/') {
                    if (!b)
                        throw 1;
                    v = a / b;
                } else {
                    if (b < 1 || b > 10)
                        throw 1;
                    v = 1;
                    while (b--)
                        v = checked((__int128)v * a);
                }
                stack.push_back(v);
            }
            if (stack.size() != 1)
                throw 1;
            return stack.back();
        }
    };
    
    int main() {
        string s;
        getline(cin, s);
        try {
            while (!s.empty() && isspace((unsigned char)s.back()))
                s.pop_back();
            if (s.empty() || s.back() != '@' || count(s.begin(), s.end(), '@') != 1)
                throw 1;
            s.pop_back();
            Parser p(s, false);
            cout << p.run() << "\n";
        } catch (...) {
            cout << "NO\n";
        }
    }
    
    • 1

    信息

    ID
    2090
    时间
    1000ms
    内存
    64MiB
    难度
    普及+
    标签
    递交数
    0
    已通过
    0
    上传者