1 条题解
-
0
这个思路是听我教练讲的,感觉很妙。
这道题你只需要会表达式求值这道经典题目,其实就可以很轻松地解出来。
首先以下是表达式求值代码:
#include <bits/stdc++.h> using namespace std; stack<int> stk; stack<char> op; char s[1000010]; map<char,int> mp; void calc() { int b=stk.top();stk.pop(); int a=stk.top();stk.pop(); int num=0; if(op.top()=='+') num=a+b; else if(op.top()=='-') num=a-b; else if(op.top()=='*') num=a*b; else { if(b==0) puts("error"),exit(0); else num=a/b; } stk.push(num); op.pop(); return; } void solve() { int t=strlen(s); for(int i=0;i<t;i++) { if(isdigit(s[i])) { int j=i; int num=0; while(j<t && isdigit(s[j])) { num=num*10+s[j]-'0'; j++; } i=j-1; stk.push(num); } else { if(s[i]=='-') { if(i==0 || s[i-1]=='(') { stk.push(0),op.push('-'); } } if(s[i]=='(') op.push('('); if(s[i]==')') { while(!op.empty() && op.top()!='(') { calc(); } if(!op.empty()) op.pop(); } if(s[i]!='(' && s[i]!=')') { while(!op.empty() && mp[op.top()]>=mp[s[i]]) { calc(); } op.push(s[i]); } } } while(!op.empty() && op.top()!='(') { calc(); } printf("%s=%d",s,stk.top()); } int main() { scanf("%s",s); mp['+']=1; mp['-']=1; mp['*']=2;//mp表示优先级的大小。 mp['/']=2; solve(); }首先我们考虑用以上代码算出此题中表达式的结果。
很简单,首先就是把
map的优先级符号改了,然后把calc函数里面的内容改了,剩下的细节就不多说了。然后下面就是重点了,如何算出短路的个数?
以下拿位运算符号或来举例。
首先,假设现在有一个符号或:

我们已经通过表达式求值算出了他左右两边的值,假设为 和 。再假设我们已经算出左右两边或的短路,与的短路,我们分别假设为 ,,,。
那么如下图:

如果 为为 ,这里是不是就构成一个短路了?
那么其实,此表达式的短路数就是 的短路或次数加一(与和或分开来算),与运算短路与 的短路次数相同。因为题目要求,所以我们 算出来的短路次数就直接作废。多加的一就是现在或的短路。
而如果 为 ,那么不构成短路, 和 的值都有效。所以这个表达式的短路数就是 的短路数加 的短路数。
而位运算与其实也可以像或一样分类讨论运算。
这便是思路的核心。
可能有人会问,怎么实现?
其实我们只需要套个表达式求值模板跑一遍就好了。
因为表达式求值的模板可以算出优先级高的部分,然后慢慢算出低的部分,每次运算时,都是拿栈顶的两个元素计算,我们只需要按照上述内容,用栈顶的两个元素进行短路合并就好了。
可能我语文水平不行,上面讲的很多内容大家会看不懂,但是你们看完代码一定会茅塞顿开的。
#include <bits/stdc++.h> using namespace std; stack<int> stk; stack<pair<int,int>> duan; stack<char> op; char s[1000010]; map<char,int> mp; void merge_duan(pair<int,int> aa,pair<int,int> bb,int a,int b,char op) { pair<int,int> c; if(a==1 && op=='|') { c.first=aa.first+1;//跟上述内容相符。 c.second=aa.second; } else if(a==0 && op=='&') { c=aa; c.second++;//如果a为0并且符号为与,那么构成了一个短路,为a的与的短路数加一,或的短路不变,b的短路数直接作废。 } else { c.first=aa.first+bb.first; c.second=aa.second+bb.second; } duan.push(c);//把算好的短路次数放回去,准备下一次运算。 } void calc() { int b=stk.top();stk.pop(); int a=stk.top();stk.pop();//表达式求值模板。 int num=0; pair<int,int> bb=duan.top();duan.pop(); pair<int,int> aa=duan.top();duan.pop();//跟表达式求值一样,每次从栈顶弹出两个元素进行运算。 merge_duan(aa,bb,a,b,op.top());//合并。 if(op.top()=='|') num=a|b; else if(op.top()=='&') num=a&b; stk.push(num); op.pop(); return; } void solve() { int t=strlen(s); for(int i=0;i<t;i++) { if(isdigit(s[i])) stk.push(s[i]-'0'),duan.push({0,0});//如果遇到数就直接放入栈中,并且为这个数创建一个新的空间,代表他目前算出的短路次数,第一个代表或,第二个代表与。 else { if(s[i]=='(') op.push('('); if(s[i]==')') { while(!op.empty() && op.top()!='(') calc();//表达式求值模板。 if(!op.empty()) op.pop(); } if(s[i]!='(' && s[i]!=')') { while(!op.empty() && mp[op.top()]>=mp[s[i]]) calc(); op.push(s[i]); } } } while(!op.empty()) calc(); printf("%d\n",stk.top()); printf("%d %d",duan.top().second,duan.top().first); } int main() { scanf("%s",s); mp['|']=1; mp['&']=2;//优先级。 solve(); }这道题其实感觉没有绿题的难度,就是跑了一遍表达式求值。
- 1
信息
- ID
- 1980
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 8
- 标签
- 递交数
- 23
- 已通过
- 4
- 上传者