1 条题解
-
0
思路与算法
先检查唯一末尾@,再按语法把中缀转换为后缀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