【碳硫磷模拟赛】消失的+和* (树形DP)
好久没做过这么恶心的DP题了
题面
题面很简单,有一个计算式,由+号、*号、括号和小于10的正整数组成,现在所有的+和*(由于属于违禁词而)都被-号给和谐掉了,现在要求所有可能的原计算式的结果之和。
你知道的信息:计算式总长度
n
∈
[
1
,
1
0
5
]
n\in[1,10^5]
n∈[1,105](其中保证-号总数
m
≤
2500
m\leq2500
m≤2500),原计算式的+号总数
k
∈
[
0
,
m
]
k\in[0,m]
k∈[0,m] ,被和谐后的计算式(含括号)。
题解
括号表示了计算间的优先关系,我们可以通过这种关系建棵树,子节点比父节点先算。
然后,设计DP状态:
d
p
[
i
]
[
j
]
.
s
u
m
dp[i][j].sum
dp[i][j].sum 表示该子树
i
i
i 内存在
j
j
j 个+号的所有算式结果之和,
d
p
[
i
]
[
j
]
.
c
n
t
dp[i][j].cnt
dp[i][j].cnt 表示该子树
i
i
i 内存在
j
j
j 个+号的算式总数。此处
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 是一个二元组。
经典的树形背包DP枚举+转移思路:记录前面儿子的答案,与下一个儿子合并。此时“前面儿子”不一定两端有括号,但下一个儿子一定是一个整体。
那么对于两个算式间用+号相连(
C
=
A
+
B
C=A+B
C=A+B),有转移:
d
p
[
C
]
[
j
+
k
+
1
]
←
(
d
p
[
A
]
[
j
]
.
s
u
m
∗
d
p
[
B
]
[
k
]
.
c
n
t
+
d
p
[
B
]
[
k
]
.
s
u
m
∗
d
p
[
A
]
[
j
]
.
c
n
t
,
d
p
[
A
]
[
j
]
.
c
n
t
∗
d
p
[
B
]
[
k
]
.
c
n
t
)
dp[C][j+k+1]\leftarrow (dp[A][j].sum*dp[B][k].cnt+dp[B][k].sum*dp[A][j].cnt~,\\dp[A][j].cnt*dp[B][k].cnt)
dp[C][j+k+1]←(dp[A][j].sum∗dp[B][k].cnt+dp[B][k].sum∗dp[A][j].cnt ,dp[A][j].cnt∗dp[B][k].cnt)
但是对于乘法(
C
=
A
∗
(
B
)
C=A*(B)
C=A∗(B))的情况就有困难,由于前一个算式不一定两端有括号,所以
B
B
B 只能乘
A
A
A 的最后一项。那我们就把
A
A
A 的所有情况下的最后一项拿出来求和,记为
g
[
A
]
[
.
.
.
]
g[A][...]
g[A][...](不是二元组),然后可以有一个复杂的转移:
d
p
[
C
]
[
j
+
k
]
←
(
d
p
[
B
]
[
k
]
.
s
u
m
∗
g
[
A
]
[
j
]
+
(
d
p
[
A
]
[
j
]
.
s
u
m
−
g
[
A
]
[
j
]
)
∗
d
p
[
B
]
[
k
]
.
c
n
t
,
d
p
[
A
]
[
j
]
.
c
n
t
∗
d
p
[
B
]
[
k
]
.
c
n
t
)
g
[
C
]
[
j
+
k
+
1
]
←
d
p
[
B
]
[
k
]
.
s
u
m
∗
d
p
[
A
]
[
j
]
.
c
n
t
g
[
C
]
[
j
+
k
]
←
g
[
A
]
[
j
]
∗
d
p
[
B
]
[
k
]
.
s
u
m
dp[C][j+k]\leftarrow \Big(dp[B][k].sum*g[A][j]+(dp[A][j].sum-g[A][j])*dp[B][k].cnt~,\\ dp[A][j].cnt*dp[B][k].cnt\Big)\\ g[C][j+k+1]\leftarrow dp[B][k].sum*dp[A][j].cnt\\ g[C][j+k]\leftarrow g[A][j]*dp[B][k].sum
dp[C][j+k]←(dp[B][k].sum∗g[A][j]+(dp[A][j].sum−g[A][j])∗dp[B][k].cnt ,dp[A][j].cnt∗dp[B][k].cnt)g[C][j+k+1]←dp[B][k].sum∗dp[A][j].cntg[C][j+k]←g[A][j]∗dp[B][k].sum
复杂度是经典的树上背包DP时间复杂度,
O
(
n
2
)
O(n^2)
O(n2) 。
有几点要注意的:
- n
n
n 很大,
m
m
m 很小,说明括号可能很多,得缩掉一些儿子数只有1的废点。
- 注意转移的先后顺序。
- 注意子树 size ,边界情况卡准。
- 回溯的时候,由于在算式两边加上了括号,要把所有的
g
[
i
]
[
j
]
g[i][j]
g[i][j] 赋值为
d
p
[
i
]
[
j
]
.
s
u
m
dp[i][j].sum
dp[i][j].sum。
CODE
#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<ctime>
#include<queue>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 2505
#define LL long long
#define ULL unsigned long long
#define UI unsigned int
#define DB double
#define ENDL putchar('\n')
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
#define eps (1e-4)
LL read() {
LL f=1,x=0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f*x;
}
void putpos(LL x) {
if(!x) return ;
putpos(x/10); putchar('0'+(x%10));
}
void putnum(LL x) {
if(!x) putchar('0');
else if(x < 0) putchar('-'),putpos(-x);
else putpos(x);
}
void AIput(LL x,char c) {putnum(x);putchar(c);}
const int MOD = 1000000007;
int n,m,s,o,k;
int le;
char ss[100005];
int cnd,sz[MAXN];
struct it{
int x,y;it(){x=y=0;}
it(int X,int Y){x=X;y=Y;}
};
it operator + (it a,it b) {return it((a.x+b.x)%MOD,(a.y+b.y)%MOD);}
it Plus(it a,it b) {return it((a.x*1ll*b.y%MOD+a.y*1ll*b.x%MOD)%MOD,a.y*1ll*b.y%MOD);}
it Mult(it a,it b) {return it(a.x*1ll*b.x%MOD,a.y*1ll*b.y%MOD);}
it dp[MAXN][MAXN];
int g[MAXN][MAXN];
int dfs(int ad) {
if(ss[ad] != '(') {
int nm = ss[ad]-'0';
int x = ++ cnd;
sz[x] = 1;
for(int i = 1;i <= m;i ++) dp[x][i] = it(),g[x][i] = 0;
dp[x][0] = it(nm,1);
g[x][0] = nm;
return x;
}
int le = 0,cc = 1,st = ad;
vector<int> v;
v.push_back(0);
while(cc) {
ad ++;
if(ss[ad] != '-') {
if(ss[ad] == ')') cc --;
else {
if(cc == 1) v.push_back(dfs(ad)),le ++;
if(ss[ad] == '(') cc ++;
}
}
}
int tl = cnd+1;
int siz = sz[v[1]],las = v[1];
for(int i = 2;i <= le;i ++) {
int y = v[i],p = v[i-1];
las = y;
siz += sz[y];
for(int j = 0;j < siz;j ++) dp[tl][j] = it(),g[tl][j] = 0;
for(int j = 0;j < sz[y];j ++) {
for(int k = 0;k < siz-sz[y];k ++) {
int nm = (dp[y][j].x *1ll* g[p][k] % MOD + (dp[p][k].x+MOD-g[p][k]) % MOD *1ll* dp[y][j].y % MOD) % MOD;
dp[tl][j+k] = dp[tl][j+k] + it(nm,dp[y][j].y *1ll* dp[p][k].y % MOD);
dp[tl][j+k+1] = dp[tl][j+k+1] + Plus(dp[y][j],dp[p][k]);
(g[tl][j+k] += g[p][k] *1ll* dp[y][j].x % MOD) %= MOD;
(g[tl][j+k+1] += dp[y][j].x *1ll* dp[p][k].y % MOD) %= MOD;
}
}
swap(dp[tl],dp[y]);
swap(g[tl],g[y]);
sz[y] = siz;
}
for(int i = 0;i < siz;i ++) g[las][i] = dp[las][i].x;
return las;
}
int main() {
freopen("operator.in","r",stdin);
freopen("operator.out","w",stdout);
le = read();m = read();
scanf("%s",ss + 1);
ss[0] = '(';
ss[le+1] = ')';
int rt = dfs(0);
// printf("\n<%d>\n",n);
AIput(dp[rt][m].x,'\n');
return 0;
}
【碳硫磷模拟赛】消失的+和* (树形DP)的更多相关文章
- codehunter 「Adera 6」杯省选模拟赛 网络升级 【树形dp】
直接抄ppt好了--来自lyd 注意只用对根判断是否哟留下儿子 #include<iostream> #include<cstdio> using namespace std; ...
- 6.28 NOI模拟赛 好题 状压dp 随机化
算是一道比较新颖的题目 尽管好像是两年前的省选模拟赛题目.. 对于20%的分数 可以进行爆搜,对于另外20%的数据 因为k很小所以考虑上状压dp. 观察最后答案是一个连通块 从而可以发现这个连通块必然 ...
- 「模拟赛20190327」 第二题 DP+决策单调性优化
题目描述 小火车虽然很穷,但是他还是得送礼物给妹子,所以他前往了二次元寻找不需要钱的礼物. 小火车准备玩玩二次元的游戏,游戏当然是在一个二维网格中展开的,网格大小是\(n\times m\)的,某些格 ...
- 模拟赛20181015 Uva1078 bfs+四维dp
题意:一张网格图,多组数据,输入n,m,sx,sy,tx,ty大小,起终点 接下来共有2n-1行,奇数行有m-1个数,表示横向的边权,偶数行有m个数,表示纵向的边权 样例输入: 4 4 1 1 ...
- 【noip模拟赛7】上网 线性dp
描述 假设有n个人要上网,却只有1台电脑可以上网.上网的时间是从1 szw 至 T szw ,szw是sxc,zsx,wl自创的时间单位,至于 szw怎么换算成s,min或h,没有人清楚.依次给出每个 ...
- 【noip模拟赛5】任务分配 降维dp
描述 现有n个任务,要交给A和B完成.每个任务给A或给B完成,所需的时间分别为ai和bi.问他们完成所有的任务至少要多少时间. 输入 第一行一个正整数n,表示有n个任务.接下来有n行,每行两个正整数a ...
- 2015年第六届蓝桥杯省赛T10 生命之树(树形dp+Java模拟vector)
生命之树 在X森林里,上帝创建了生命之树. 他给每棵树的每个节点(叶子也称为一个节点)上,都标了一个整数,代表这个点的和谐值. 上帝要在这棵树内选出一个非空节点集S,使得对于S中的任意两个点a,b,都 ...
- (计数器)NOIP模拟赛(神奇的数位DP题。。)
没有原题传送门.. 手打原题QAQ [问题描述] 一本书的页数为N,页码从1开始编起,请你求出全部页码中,用了多少个0,1,2,…,9.其中—个页码不含多余的0,如N=1234时第5页不是00 ...
- 「模拟赛20191019」B 容斥原理+DP计数
题目描述 将\(n\times n\)的网格黑白染色,使得不存在任意一行.任意一列.任意一条大对角线的所有格子同色,求方案数对\(998244353\)取模的结果. 输入 一行一个整数\(n\). 输 ...
随机推荐
- CSP 2021 总结
CSP 2021 总结 PJ 开题顺序:1342 应该先做 T2 ,导致我 T2 直接看错 T1.T3 T1 :直接推规律即可,考场的想法应该正确 T3 :好家伙直接 map 走起 T2 最崩溃的来了 ...
- (1)《QT+OpenGL学习之我见》初始化窗口及三个重要函数 vs+Qt
本章前言:本章讲如何利用VS和QT来创建一个基本的QOpenGLWidget窗口和有关联的三个核心函数,因为版本更新可能会有大同小异,但基本的不会有变换,有了QT的帮助,我们不需要下载opengL.g ...
- vue大型电商项目尚品汇(后台终结篇)day06 重磅!!!
自此整个项目前后台,全部搭建完毕. 今天是最后一天,内容很多,而且也比较常用,一个图标类数据可视化,一个后台的权限管理,都是很经典的类型. 一.数据可视化 1.简介 专门的一门学科,有专门研究这个的岗 ...
- openssl客户端编程:一个不起眼的函数导致的SSL会话失败问题
我们目前大部分使用的openssl库还是基于TLS1.2协议的1.0.2版本系列,如果要支持更高的TLS1.3协议,就必须使用openssl的1.1.1版本或3.0版本.升级openssl库有可能会导 ...
- 使用强大的DBPack处理分布式事务(PHP使用教程)
主流的分布式事务的处理方案 近些年,随着微服务的广泛使用,业务对系统的分布式事务处理能力的要求越来越高. 早期的基于XA协议的二阶段提交方案,将分布式事务的处理放在数据库驱动层,实现了对业务的无侵入, ...
- go-zero微服务实战系列(十一、大结局)
本篇是整个系列的最后一篇了,本来打算在系列的最后一两篇写一下关于k8s部署相关的内容,在构思的过程中觉得自己对k8s知识的掌握还很不足,在自己没有理解掌握的前提下我觉得也很难写出自己满意的文章,大家看 ...
- Jetty 源码解析 - 流程
前言 公司实习分配给的任务是精简和优化 Jetty 框架,这里做简单的思路记录(比较乱),源码是 Jetty 7.x.x . 大体流程 Connector 接口的实现类 SelectChannelCo ...
- yum-config-manager: command not found
yum-config-manager: command not found ,这个是因为系统默认没有安装这个命令,这个命令在yum-utils 包里,可以通过命令yum -y install yum- ...
- AtCoder Beginner Contest 260 F - Find 4-cycle
题目传送门:F - Find 4-cycle (atcoder.jp) 题意: 给定一个无向图,其包含了S.T两个独立点集(即S.T内部间的任意两点之间不存在边),再给出图中的M条边(S中的点与T中的 ...
- salt stack学习笔记
saltstack运行模式: local master/minion salt ssh saltstack三大功能 远程执行命令 配置管理(状态管理) 云管理 安装: master salt-mas ...