NOIP2011pj表达式的值[树形DP 笛卡尔树 | 栈 表达式解析]
题目描述
对于1 位二进制变量定义两种运算:

运算的优先级是:
先计算括号内的,再计算括号外的。
- “× ”运算优先于“⊕”运算,即计算表达式时,先计算× 运算,再计算⊕运算。例如:计算表达式A⊕B × C时,先计算 B × C,其结果再与 A 做⊕运算。
现给定一个未完成的表达式,例如+(*_),请你在横线处填入数字0 或者1 ,请问有多少种填法可以使得表达式的值为0 。
输入输出格式
输入格式:
输入文件名为exp.in ,共 2 行。
第1 行为一个整数 L,表示给定的表达式中除去横线外的运算符和括号的个数。
第2 行为一个字符串包含 L 个字符,其中只包含’(’、’)’、’+’、’*’这4 种字符,其中’(’、’)’是左右括号,’+’、’*’分别表示前面定义的运算符“⊕”和“×”。这行字符按顺序给出了给定表达式中除去变量外的运算符和括号
输出格式:
输出文件exp.out 共1 行。包含一个整数,即所有的方案数。注意:这个数可能会很大,请输出方案数对10007 取模后的结果。
输入输出样例
4
+(*)
3
说明
【输入输出样例说明】
给定的表达式包括横线字符之后为:+(*_)
在横线位置填入(0 、0 、0) 、(0 、1 、0) 、(0 、0 、1) 时,表达式的值均为0 ,所以共有3种填法。
【数据范围】
对于20% 的数据有 0 ≤ L ≤ 10。
对于50% 的数据有 0 ≤ L ≤ 1,000。
对于70% 的数据有 0 ≤ L ≤ 10,000 。
对于100%的数据有 0 ≤ L ≤ 100,000。
对于50% 的数据输入表达式中不含括号。
-------------------------
一开始想了一个区间DP的做法f[i][j][0/1]表示i到j为0或1的方案数,内存爆的连编译都不编译
然后想到建表达式树 树形DP,白书上的方法只能拿80分
用 笛卡尔树 建表达式树
有点像treap,key按左右分,value按上下分
表达式树中key就是顺序,本来就按照这个顺序;value是算术优先级,设括号个数为p,'+':p*2+1 '*':p*2+2,value小的在上面
笛卡尔树有O(n)的建树方法:
可以发现key本来有序,新加的元素只能在当前的右链上,有可能吧本来右链上一些元素转到左子树上
用一个stack维护右链上的元素就好了,每次找第一个<=当前的
//
// main.cpp
// 表达式的值树形dp
//
// Created by Candy on 9/6/16.
// Copyright ? 2016 Candy. All rights reserved.
// #include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int N=,MOD=;
int n;
char s[N];
struct node{
int ls,rs;
char op;
}tree[N*];
int cnt=,w[N],root=;
void build(){
int p=,cnt=;
for(int i=;i<=n;i++){
if(s[i]=='(') p++;if(s[i]==')') p--;
if(s[i]=='+') {w[++cnt]=p*+;
tree[cnt].op=s[i];
}
if(s[i]=='*') w[++cnt]=p*+,tree[cnt].op=s[i];;
} int st[N],k,top=-;
for (int i=;i<=cnt;i++)
{
k = top;
while (k >= && w[st[k]] > w[i]) k--;
if(k!=-) tree[st[k]].rs=i;
if (k < top) tree[i].ls=st[k+];
st[++k] = i;
top=k;
}
root=st[];
}
int f[N][];
void dp(int i){//printf("dp %d\n",i);
if(i==) return;
if(f[i][]!=) return;
int ls=tree[i].ls,rs=tree[i].rs;char op=tree[i].op;
dp(ls);dp(rs);
if(op=='+'){
f[i][]=f[ls][]*f[rs][];
f[i][]=f[ls][]*f[rs][]+f[ls][]*f[rs][]+f[ls][]*f[rs][];
}
if(op=='*'){
f[i][]=f[ls][]*f[rs][];
f[i][]=f[ls][]*f[rs][]+f[ls][]*f[rs][]+f[ls][]*f[rs][];
}
f[i][]%=MOD;f[i][]%=MOD;
}
int main(int argc, const char * argv[]) {
scanf("%d%s",&n,s+);
build();
f[][]=f[][]=;
dp(root);
printf("%d",f[root][]%MOD);
return ;
}
当然也可以用stack做,一个操作符栈一个数据栈,数据栈中是0/1的方案数
一开始push一个empty,以后每次一个+ *都push一个empty
//from 题解
//Candy?修改
#include<cstdio>
#include<cstring>
const int mod=;
struct node{
int a,b;
}f[];
const node emp=(node){,};
char s[];
char st[];int n,tp=,fp=; void cal(char op,node &a,node &b){
if(op=='+') a.b=(a.b*(b.a+b.b)+a.a*b.b)%mod,a.a=a.a*b.a%mod;
else a.a=(a.a*(b.a+b.b)+a.b*b.a)%mod,a.b=a.b*b.b%mod;
} int main(){
scanf("%d%s",&n,s);
st[++tp]='('; f[++fp]=emp;
s[n++]=')';
for(int i=;i<n;i++){
if(s[i]=='(')st[++tp]='(';
else if(s[i]==')'){
for(;st[tp]!='(';tp--,fp--)
cal(st[tp],f[fp-],f[fp]);//pop 2 push 1
tp--;// (
}
else{
for(;st[tp]<=s[i]&&st[tp]!='(';tp--,fp--)// '*' < '+'
cal(st[tp],f[fp-],f[fp]);
st[++tp]=s[i],f[++fp]=emp;//every +/* with a number
}
}
return!printf("%d\n",f[].a%mod);
}
NOIP2011pj表达式的值[树形DP 笛卡尔树 | 栈 表达式解析]的更多相关文章
- HDU 1506 Largest Rectangle in a Histogram(单调栈、笛卡尔树)
题意:给定n个连续排列的矩形的高,矩形的宽都为1.问最大矩形覆盖. 例如:n = 7,h[i] = (2 1 4 5 1 3 3),最大覆盖为8. Sample Input 7 2 1 4 5 1 3 ...
- BZOJ2616 SPOJ PERIODNI(笛卡尔树+树形dp)
考虑建一棵小根堆笛卡尔树,即每次在当前区间中找到最小值,以最小值为界分割区间,由当前最小值所在位置向两边区间最小值所在位置连边,递归建树.那么该笛卡尔树中的一棵子树对应序列的一个连续区间,且根的权值是 ...
- 【BZOJ2616】SPOJ PERIODNI 笛卡尔树+树形DP
[BZOJ2616]SPOJ PERIODNI Description Input 第1行包括两个正整数N,K,表示了棋盘的列数和放的车数. 第2行包含N个正整数,表示了棋盘每列的高度. Output ...
- BZOJ.2616.SPOJ PERIODNI(笛卡尔树 树形DP)
BZOJ SPOJ 直观的想法是构建笛卡尔树(每次取最小值位置划分到两边),在树上DP,这样两个儿子的子树是互不影响的. 令\(f[i][j]\)表示第\(i\)个节点,放了\(j\)个车的方案数. ...
- bzoj 2616 SPOJ PERIODNI——笛卡尔树+树形DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2616 把相同高度的连续一段合成一个位置(可能不需要?),用前缀和维护宽度. 然后每次找区间里 ...
- 洛谷 P5044 - [IOI2018] meetings 会议(笛卡尔树+DP+线段树)
洛谷题面传送门 一道笛卡尔树的 hot tea. 首先我们考虑一个非常 naive 的区间 DP:\(dp_{l,r}\) 表示区间 \([l,r]\) 的答案,那么我们考虑求出 \([l,r]\) ...
- codevs2178 表达式运算Cuties[笛卡尔树]
2178 表达式运算Cuties 时间限制: 1 s 空间限制: 32000 KB 题目等级 : 大师 Master 题解 查看运行结果 题目描述 Description 给出一个表达 ...
- POJ 3162 bit区间查询最值+树形DP
POJ 3162 『题目链接』POJ 3162 『题目类型』bit区间查询最值+树形DP ✡Problem: 一棵n个节点的树.wc爱跑步,跑n天,第i天从第i个节点开始跑步,每次跑到距第i个节点最远 ...
- bzoj2616: SPOJ PERIODNI——笛卡尔树+DP
不连续的处理很麻烦 导致序列DP又找不到优秀的子问题 自底向上考虑? 建立小根堆笛卡尔树 每个点的意义是:高度是(自己-father)的横着的极大矩形 子问题具有递归的优秀性质 f[i][j]i为根子 ...
随机推荐
- ae柱状图
- Ubuntu开机黑屏,无法进入系统
今天早上起来开机发现Ubuntu进不去了,启动项选择之后长时间的black of screen,击键盘.点鼠标毫无反应,后来实在等不下去了就按了一下电源键,以平时的性格就是强制关机的,这次轻轻碰一下就 ...
- iOS开发-canOpenURL: failed for URL: "xx" - error:"This app is not allowed to query for scheme xx"
转载自:http://www.jianshu.com/p/e38a609f786e
- Android 查看手机中所有进程
真机测试的时候发现DDMS对进程的显示很不给力,一些进程管理工具又不显示包名. 所以就自己写了一个小程序,查看自己手机中的进程,显示当前时间和进程的包名: 程序运行截图: 布局: <Linear ...
- gif动图快速制作方法(附工具)
现在写博客或是wiki的过程中,会经常引用到图片,特别是客户端经常与页面相关所以截图不可避.但是越来越多的效果仅仅一张图片是无法清楚的描述.并且博客或是wiki也是支持gif图的.gif图的制作方法有 ...
- Java继承中的转型及其内存分配
看书的时候被一段代码能凌乱啦,代码是这样的: package 继承; abstract class People { public String tag = "疯狂Java讲义"; ...
- 在Json解析过程中,我为什么用object1.optInt ,和 object1.optString
今天在做Json解析的时候,出现了一段代码没执行的问题,于是找了一下原因: 1.原代码是: 发现 红色的一句 没有执行,查看控制台发现了异常 2.修复bug ,正确的代码为 3.总结 ...
- 拓展:使用终端创建、编译、链接OC…
本文介绍一下如何使用Mac OS X自带终端快速创建.编译.链接OC程序. 1.打开终端 顺序:打开Finder——应用程序——实用工具——终端 2.打开需要存放 .m 文件的路径(比如我需要放到桌面 ...
- 【代码笔记】iOS-平面化的饼图
一,效果图. 二,工程图. 三,代码. RootViewController.m - (void)viewDidLoad { [super viewDidLoad]; // Do any additi ...
- nginx 配置优化的几个参数(转)
nginx配置文件里面需要注意的一些参数 worker_processes 8 nginx要开启的进程数 一般等于cpu的总核数 其实一般情况下开4个或8个就可 我开2个 以了 多了没有太多用每个n ...