[洛谷 P1310]表示式的值 --- 表示式樹(中綴轉字尾)+DP
阿新 • • 發佈:2018-11-10
傳送門:洛谷 P1310
題目描述
對於1 位二進位制變數定義兩種運算:
運算的優先順序是:
先計算括號內的,再計算括號外的。
“ ”運算優先於“ ”運算,即計算表示式時,先計算 運算,再計算 運算。例如:計算表示式 時,先計算 ,其結果再與 做 運算。
現給定一個未完成的表示式,例如 ,請你在橫線處填入數字 或者 ,請問有多少種填法可以使得表示式的值為 。
分析
無論是用棧做還是用樹做,其目的都是理清
順序。
注意題目省略了數字(類比吧),自行腦補一下
一.中綴表示式轉字尾表示式
(放在前面強調)對於本題來說,數字要自己補( 的方案數均為 )
對於一棵表示式樹而言,葉子節點全是數字,非葉子節點全是操作符
基於手動演算法:
-
補全括號:
-
將運算子放在括號後面:
-
去掉所有括號:
稍加分析改進後(不必加括號),就有了如下演算法:
-
判斷兩邊是否有多餘的括號,有的話去掉
-
從後往前(正常計算時,左子樹會先計算,所以,對於同級的操作符來說,前面的歸為左子樹),找到優先順序最低且最後面的運算子,以它為父親節點。
-
左右子樹遞迴處理
二.DP
令f[i][0/1]表示子樹i的為0/1的方案數
友情提示:注意取模(否則 )
if(節點i為 ‘+’ )
f[i][0] = f[lch][0] * f[rch][0];
f[i][1] = f[lch][0] * f[rch][1] + f[lch][1] * f[rch][0] + f[lch][1] * f[rch][1];
if(節點i為 '*' )
f[i][0] = f[lch][0] * f[rch][0] + f[lch][0] * f[rch][1] + f[lch][1] * f[rch][0];
f[i][1] = f[lch][1] * f[rch][1];
程式碼
#include <cstdio>
#include <cstdlib>
#include <stack>
#define IL inline
using namespace std;
IL int read()
{
int sum = 0, k= 1;
char c = getchar();
for(;'0' > c || c > '9'; c = getchar())
if(c == '-') k = 0;
for(;'0' <= c && c <= '9'; c = getchar())
sum = sum * 10 + c - '0';
return k ? sum : -sum;
}
const int mo(10007);
int n;
char mp[100005];
int to[100005];
stack<int>stk;
IL int turn(char c)
{
if(c == '+') return 1;
if(c == '*') return 2;
return 3;
}
IL int find(int l, int r)
{
int p = -1;
for(; r >= l;)
if(mp[r] == ')')
{
r = to[r] - 1;
}else
{
if(p == -1 || turn(mp[r]) < turn(mp[p])) p = r;
if(mp[p] == '+') return p;
--r;
}
return p;
}
struct node
{
int x, y;
IL node(int x_ = 0, int y_ = 0)
{
x = x_; y = y_;
}
};
IL node dfs(int l, int r)
{
if(l > r) return node(1, 1);
if(mp[l] == '(' && mp[r] == ')' && to[r] == l) { ++l; --r; }
if(l > r) return node(1, 1);
int p = find(l, r);
//printf("%d %c\n", p, mp[p]);
node tmp1 = dfs(l, p - 1), tmp2 = dfs(p + 1, r);
if(mp[p] == '+') return node( tmp1.x * tmp2.x % mo, (tmp1.x * tmp2.y % mo + tmp1.y * tmp2.x % mo + tmp1.y * tmp2.y % mo) % mo);
if(mp[p] == '*') return node( (tmp1.x * tmp2.x % mo + tmp1.x * tmp2.y % mo + tmp1.y * tmp2.x % mo) % mo, tmp1.y * tmp2.y % mo);
}
int main()
{
n = read();
char c;
for(int i = 1; i <= n; ++i)
{
scanf(" %c", &c);
mp[i] = c;
if(c == '(') stk.push(i); else
if(c == ')') { to[i] = stk.top(); stk.pop(); }
}
printf("%d\n", dfs(1, n).x);
return 0;
}