【模擬 + 棧】AcWing 151. 表示式計算4
阿新 • • 發佈:2022-01-12
這題括號多餘的情況好惡心 orz,以及負數的情況也增加了這題的難度。
分析
首先,解決一般的中綴表示式轉字尾表示式問題:
這裡的運算子包括
+,-,*,/,^
,當然,擴大運算子包含的集合的時候我們也可以類似推廣。
考慮用一個答案棧 res
以及運算子棧 ops
來操作。
- 遇到數字的時候,將它丟入
res
。 - 遇到左括號的時候,將它丟入
ops
。 - 遇到右括號的時候,開始對
ops
執行出棧操作直到遇到左括號。 - 遇到運算子的時候,只要
ops
棧頂的運算子優先順序高於當前運算子,就一直對ops
執行出棧操作。
這樣我們就可以將中綴轉字尾了。
下面對字尾表示式求值:
考慮用一個棧維護,
遍歷字尾表示式,當遇到數
遍歷完字尾表示式後棧只剩一個數,這就是答案。
至此,原理講述完畢。
但這題很毒瘤,會有括號多餘的情況以及負數的情況。
接下來的操作由為本人亂搞得出,如果找到 hack 資料可以發給我 qwq~,但目前我試了許多奇怪的資料都可以過。
- 對於括號多餘的情況,考慮對原序列
s
進行一遍類似於括號匹配的操作:維護兩個變數cntL, cntR
,見程式碼:
int cntL=0, cntR=0; for(auto i: s){ if(i=='(') cntL++; else if(i==')' && cntL) cntL--; else if(i==')' && !cntL) cntR++; }
- 然後對於負數的情況,例如
-1+3
,將-1
替換為(0-1)*
。
實現
// Problem: 表示式計算4 // Contest: AcWing // URL: https://www.acwing.com/problem/content/153/ // Memory Limit: 64 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) #include<bits/stdc++.h> using namespace std; #define debug(x) cerr << #x << ": " << (x) << endl #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define dwn(i,a,b) for(int i=(a);i>=(b);i--) #define pb push_back #define all(x) (x).begin(), (x).end() #define int long long using pii = pair<int, int>; using ll = long long; inline void read(int &x){ int s=0; x=1; char ch=getchar(); while(ch<'0' || ch>'9') {if(ch=='-')x=-1;ch=getchar();} while(ch>='0' && ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar(); x*=s; } map<char, int> mp; string c2str(char ch){ string s; s+=ch; return s; } vector<string> get(string s){ vector<string> res; stack<char> ops; rep(j,0,s.size()-1){ char i=s[j]; if(isdigit(i)){ string num; while(j<s.size() && isdigit(s[j])){ num+=s[j]; j++; } res.pb(num); j--; } else if(i=='(') ops.push('('); else if(i==')'){ while(ops.top()!='('){ res.pb(c2str(ops.top())); ops.pop(); }; ops.pop(); } else{ while(ops.size() && mp[ops.top()]>=mp[i]){ res.pb(c2str(ops.top())); ops.pop(); } ops.push(i); } } while(ops.size()) res.pb(c2str(ops.top())), ops.pop(); return res; } int to_int(string s){ int res=0; for(auto i: s) res=res*10+i-'0'; return res; } int getV(int a, int b, string op){ if(op=="+") return a+b; if(op=="-") return a-b; if(op=="*") return a*b; if(op=="/") return a/b; if(op=="^"){ int res=1; for(; b; b>>=1, a*=a) if(b&1) res=res*a; return res; } } int cal(vector<string> s){ stack<int> stk; for(auto i: s){ if(!mp.count(i[0])) stk.push(to_int(i)); else{ int a=stk.top(); stk.pop(); int b=stk.top(); stk.pop(); stk.push(getV(b, a, i)); } } return stk.top(); } signed main(){ mp['(']=0; mp['+']=mp['-']=1; mp['*']=mp['/']=2; mp['^']=3; string str; cin>>str; string s; rep(i,0,str.size()-1){ if(i && str[i]=='-' && !isdigit(str[i-1]) || !i && str[i]=='-'){ if(i && str[i-1]==')') s+="+(0-1)*"; else s+="(0-1)*"; } else s+=str[i]; } int cntL=0, cntR=0; for(auto i: s){ if(i=='(') cntL++; else if(i==')' && cntL) cntL--; else if(i==')' && !cntL) cntR++; } while(cntL--) s+=')'; auto tmp=s; s=""; while(cntR--) s+='('; s+=tmp; cout<<cal(get(s))<<endl; return 0; }