洛谷P1981《表示式求值》
阿新 • • 發佈:2020-10-14
原更新日期:2018-10-06 21:28:34
新技能:手寫計算器
題目描述
給定一個只包含加法和乘法的算術表示式,請你程式設計計算表示式的值。
Input / Output 格式 & 樣例
輸入格式
一行,為需要你計算的表示式,表示式中只包含數字、加法運算子“\(+\)”和乘法運算子“ \(\times\) ”,且沒有括號,所有參與運算的數字均為 \(0\) 到 \(2^{31}\)的整數。
輸入資料保證這一行只有 \(0−9\)、\(+\)、 \(\times\) 這 \(12\) 種字元。
輸出格式
一個整數,表示這個表示式的值。
注意:當答案長度多於 4 位時,請只輸出最後 4 位,前導 0 不輸出。
輸入樣例
Case #1:
1+1*3+4
Case #2:
1+1234567890*1
Case #3:
1+1000000003*1
輸出樣例
Case #1:
8
Case #2:
7891
Case #3:
4
資料範圍
對於 30%的資料,0≤表示式中加法運算子和乘法運算子的總數≤100;
對於 80%的資料,0≤表示式中加法運算子和乘法運算子的總數≤1000;
對於100%的資料,0≤表示式中加法運算子和乘法運算子的總數≤100000。
解題思路
我們開兩個單調棧,一個棧num
來儲存數字,一個棧operators
來儲存符號
其中operators
的操作邏輯是這樣的:
- 首先把
~
push進去,作為一個佔位符 - 我們對運算子標一個優先順序,規定
~ < + < *
- 當push進去的運算子優先順序比棧頂的低時,解決所有優先順序低的運算子(維護單調性質)再push進去
- 當push進去的運算子優先順序比棧頂的高時,不用管,直接push進去(滿足單調性質)
處理完輸入之後,我們再對數字棧裡剩下的數字進行處理
最後輸出即可
程式碼實現
這裡面所有的註釋都是我在DEBUG的時候手推的樣例
/* -- Basic Headers -- */ #include <iostream> #include <cstdio> #include <cstring> #include <cctype> #include <algorithm> /* -- STL Iterators -- */ #include <vector> #include <string> #include <stack> #include <queue> /* -- External Headers -- */ /* -- Defined Functions -- */ #define For(a,x,y) for (int a = x; a <= y; ++a) #define Forw(a,x,y) for (int a = x; a < y; ++a) #define Bak(a,y,x) for (int a = y; a >= x; --a) /* -- Defined Words -- */ using namespace std; namespace FastIO { void DEBUG(char comment[], int x) { cerr << comment << x << endl; } inline int getint() { int s = 0, x = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') x = -1; ch = getchar(); } while (isdigit(ch)) { s = s * 10 + ch - '0'; ch = getchar(); } return s * x; } inline void __basic_putint(int x) { if (x < 0) { x = -x; putchar('-'); } if (x >= 10) __basic_putint(x / 10); putchar(x % 10 + '0'); } inline void putint(int x, char external) { __basic_putint(x); putchar(external); } } namespace Solution { stack<int> num; stack<int> operators; // 1: + - // 2: * / const int MOD = 10000; long long int ans = 0; bool Priority(char op1, char op2) { // false -> op1 is lower // true -> op1 is higher if (op1 == op2) return false; if (op1 == '~') return false; if (op1 == '+' && op2 == '*') return false; if (op1 == '*' && op2 == '+') return true; } } int main(int argc, char *const argv[]) { #ifdef HANDWER_FILE freopen("testdata.in", "r", stdin); freopen("testdata.out", "w", stdout); #endif using namespace Solution; using namespace FastIO; // 1+1*3+4 int ans = 0, now = 0; char op = 0; cin >> ans; // 1 num.push(ans % MOD); // < 1 operators.push('~'); // < ~ while (cin >> op >> now) { // +1 // *3 // +4 char op1 = operators.top(); // ~ // + // * while (Priority(op1, op)) { // false // false // true // false int opNum = num.top(); // // // 3 num.pop(); // // // < 1 1 int opNum2 = num.top(); // // // 1 num.pop(); // // // < 1 if (op1 == '+') num.push((opNum + opNum2) % MOD); // // // false if (op1 == '*') num.push(opNum * opNum2 % MOD); // // // < 1 3 operators.pop(); // < + op1 = operators.top(); // + } operators.push(op); // < + // < + * // < + + num.push(now); // < 1 1 // < 1 1 3 // < 1 3 4 } while (num.size() > 1) { // true // true // false int op = num.top(); // 4 // 7 num.pop(); // < 1 3 // < 1 int op2 = num.top(); // 3 // 1 num.pop(); // < 1 // < char ope = operators.top(); operators.pop(); if (ope == '+') num.push((op + op2) % MOD); // < 1 7 // < 8 if (ope == '*') num.push(op * op2 % MOD); } FastIO::putint(num.top() % MOD, '\n'); // 8 return 0; }