Codeforces 115 D
题意:给一个没有括号的表达式,问有多少种添加括号的方法使得这是一个合法的表达式?输入可能有正负号、加减乘除、数字。
思路1:
这是不能过的\(naive\)的\(dp\)。
考虑\(dp(l,r)\)表示从第\(l\)个字符到第\(r\)个字符有多少种添加括号的方法。
转移的时候就枚举当前最后一次运算。
思路2:
这是\(tourist\)的神奇\(dp\)。
考虑\(dp(i,j)\)表示第\(i\)个正负符号到第\(j\)个连续符号段连着的那个数字有多少种添加括号的方法。
转移的时候是枚举最后一次运算时哪一个连续符号段的第一个(因为只有这一个是二元运算符
那么就发现我们需要记录一个从连续符号段的第一个到连续符号段的第一个正负符号的映射,记为\(st\)。
然后从\(dp(i,k)\times dp(st_{k+1},j)\)转移来。
这样就三方出奇迹了。(%%% \(tourist\))
思路3:
这是\(shik\)的神奇记忆化搜索。
首先我们把原输入变成以下段:
- 连续数字:0
- 正负(加减)符号:1
- 乘除符号:2
那么考虑\(dp(i,j)\)表示到了第\(i\)个段,打开的左括号有\(j\)个,有多少种方法。
然后考虑转移。
假如这个位置是连续数字,那么可以合上一些括号或者不合上。
否则就必须打开一个括号。
最后答案是\(dp(n,0)\)。
(话说1和2只是用来判无解的。。。
思路4:
这是ACRush的神奇三方DP。
按照shik的方法分段。
直接考虑\(dp(i,j)\)表示从第\(i\)段到第\(j\)段的答案。
然后转移的时候就是枚举中间那一个字符的位置,然后左右答案乘起来一加就可以了。
思路5:
这是\(Al.cash\)的和\(shik\)差不多的方法。
两人的状态是一样的,但是\(Al.cash\)用了前缀和来搞每次合上很多符号的操作对\(dp\)的影响。
思路6:
这是最难看懂的\(chenlijie\)神仙的方法。
首先把所有的连续符号段中的正负符号个数放到v数组中,
然后用一个\(dp\)的\(vector\)存下所有的\(dp\)值,
从后往前枚举v,对于每一个v,dp的前v+1个代表的是倒数的第*个正负字符到最后的答案。
然后把它们删掉,后面的内容做一次前缀和就竟然可以转移了!?
这。。。
感觉之前想的也不太对了。。。
其实是在思路1中\(dp\)每一次更新当前区间的时候加上的东西之和正好是后一个位置到结尾的答案。。。
这肯定是打表打出来的!
思路7:
NuM的,基本同ACRush。
把这些写完后一发交上去只过了一个。。。
其它的都是由于一个特殊情况没有考虑到:
如果第一个字母是乘号或者除号,那么无解
所以两个WA,两个RE。
然后第二发全过了。