EX 中缀表达式题解
2022liaojianxiang · · 题解
感谢洛谷把 GDKOI 放上来了!借这道题来庆祝我普及金奖!
【GDKOI2024 普及组】EX 中缀表达式的题解
在这里提出我的建议:
- 这道题建议升紫,在模拟中还有数学参入,所以难度还是比较大的,希望建议能被采纳,谢谢!
题目大意
这是一道数学、模拟题,要求计算表达式的值并且按照它规定的优先级和结合的左右顺序进行处理并模 +、* 和 ^。
前置芝士
-
后缀表达式(逆波兰式)
-
表达式树
-
扩展欧拉定理
考场上的情况(不想看的可以跳过)
先说一下我比赛时的情况:那时我非常智慧,看到这道题一眼模拟直接无脑开始狂打。像这种表达式求值的题很明显的做法是将中缀表达式转成后缀表达式,然后进行求值。因为打熟悉了中缀表达式转成后缀表达式,所以很快打完,并且 Error 判断的也比较好,最后一直过不了样例,甚至叫来老师问是不是样例出错了(因为样例有次方运算,我又把次方给进行了模运算,导致直接暴力算都是错的),最后也是不明不白地离开了考场。出来和同学讨论以后才发现次方运算的次方不可以直接模。结果还怀疑人家题出错了【捂脸】。最后居然还能拿没有次方运算的 Error 的
正解
其实就是暴力,只不过细节有亿点点多。
难点
判断不合法的 Error 情况:
首先判断不合法的中缀表达式有以下几种:
-
出现了不是数字、
+、*、^、(或)的字符; -
括号不匹配;
-
运算符没有数字在前表示优先级或者数字不在
1 到n 的范围内; -
两个括号之间为空;
-
每个字符没有对应运算的两个数字。
将中缀表达式转成后缀表达式
个人认为这是比较简单的一步,只要你学过中缀表达式转成后缀表达式。在这里还是讲一下步骤吧:
我们用一个字符栈来维护这个过程。
-
如果遇到数字,直接加入后缀表达式。
-
如果遇到字符,先判断是否有优先级更高的字符在栈中,如果高就弹出并加入后缀表达式,直到遇到优先级比它低的符号。如果在弹的过程中遇到左括号,就不再弹出;
-
如果遇到左括号,直接加入字符栈;
-
如果遇到右括号,一直弹运算符直到左括号,同时也弹掉左括号;
-
那怎么处理同优先级的左右运算呢?题目中确实有这样的规定。左结合就是从左往右运算,左边先加入的优先级更高,右结合代表从右往左运算,右边的优先级更高;
-
如果字符栈里还有剩余就全部弹出即可。
这时我们就得到了一个后缀表达式。
将次方取模时的处理(乘方运算在取模意义下的取值)
对于次方来说确实不好办的,不可以直接取模,所以这应该是最难的一个点了,我们需要用到一个数学推论:扩展欧拉定理。
这里给出式子:
我们发现不能仅仅靠后缀表达式,我们需要建立一颗后缀表达式树,因为我们需要先算出
接下来的操作对于加法和乘法是比较简单的,我们直接将它们取模返回值即可。
当我们遇到次方运算时,我们需要计算
如果互质也就是第一种情况就非常简单,求得
发现不互质的情况还是很麻烦,需要判断
这样就能发现获得了
最后发现输入的数字还有可能是一个很多位数的数字,必须用高精度来存储,只用在刚开始的数字中计算即可(因为上传的时候会模数)。建议高精度用结构体存储,并只在表达式树下层叶子节点数字计算高精度时使用,上层取模后可以直接存储。
代码有点小多,要坚持下去才能打败这种大模拟题!
Code
详见云剪贴板