传送门:洛谷 P1310
题目描述
对于1 位二进制变量定义两种运算:
运算的优先级是:
先计算括号内的,再计算括号外的。
“ × × × ”运算优先于“ ⨁ \bigoplus ⨁”运算,即计算表达式时,先计算 × × × 运算,再计算 ⨁ \bigoplus ⨁运算。例如:计算表达式 A ⨁ B × C A\bigoplus B×C A⨁B×C时,先计算 B × C B × C B×C,其结果再与 A A A 做 ⨁ \bigoplus ⨁运算。
现给定一个未完成的表达式,例如 + ( ∗ ) +(*) +(∗),请你在横线处填入数字 0 0 0或者 1 1 1 ,请问有多少种填法可以使得表达式的值为 0 0 0。
分析
无论是用栈做还是用树做,其目的都是理清
D
P
DP
DP顺序。
注意题目省略了数字(类比吧),自行脑补一下
一.中缀表达式转后缀表达式
(放在前面强调)对于本题来说,数字要自己补( 0 / 1 0/1 0/1的方案数均为 1 1 1)
对于一棵表达式树而言,叶子节点全是数字,非叶子节点全是操作符
基于手动算法:
-
补全括号: a + b ∗ c − ( d + e ) → ( ( a + ( b ∗ c ) ) − ( d + e ) ) a+b*c-(d+e) \to ((a+(b*c))-(d+e)) a+b∗c−(d+e)→((a+(b∗c))−(d+e))
-
将运算符放在括号后面: ( ( a + ( b ∗ c ) ) − ( d + e ) ) → ( ( a ( b c ) ∗ ) + ( d e ) + ) − ((a+(b*c))-(d+e)) \to ((a(bc)* )+ (de)+ )- ((a+(b∗c))−(d+e))→((a(bc)∗)+(de)+)−
-
去掉所有括号: ( ( a ( b c ) ∗ ) + ( d e ) + ) − → a b c ∗ + d e + − ((a(bc)* )+ (de)+ )- \to abc*+de+- ((a(bc)∗)+(de)+)−→abc∗+de+−
稍加分析改进后(不必加括号),就有了如下算法:
-
判断两边是否有多余的括号,有的话去掉
-
从后往前(正常计算时,左子树会先计算,所以,对于同级的操作符来说,前面的归为左子树),找到优先级最低且最后面的运算符,以它为父亲节点。
-
左右子树递归处理
二.DP
令f[i][0/1]表示子树i的为0/1的方案数
友情提示:注意取模(否则 20 20 20)
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;
}