DP系列——树形DP(Codeforces543D-Road Improvement)
一、题目链接
http://codeforces.com/problemset/problem/543/D
二、题意
给一棵树,一开始所有路都是坏的。询问,以每个节点$i$为树根,要求从树根节点到其他每个节点的路径上都满足最多只有一条边是坏的。问有多少种修路方式。输出以每个节点$i$为根节点的满足条件的修路方式。结果对$10^9+7$取模。
三、思路
假设$ans[i]$为节点$i$的答案。
定$1$为总树根。$dp[i]$表示:以节点$i$为根的子树中的修路方式。易知,$dp[i] = \prod\limits_{j}(dp[j] + 1) \% (10^9+7)$,其中$j$为$i$的子节点。
显然,$ans[1] = dp[1]$。当已知父节点$i$的$ans[i]$时,求节点$i$的子节点$j$的$ans[j]$,不难得到如下式子:
\[ans[j] = dp[j] * (\frac{dp[i]}{dp[j]+1}+1)\]
使用上述递推式,加上求$(dp[j]+1)$的逆元,能想到的样例基本都没错。提交后,会WA on 10。
WA的原因是,当$dp[j]+1=10^9+7,dp[i]\%(10^9+7)=0$时,使用上述递推式会出问题。
所以应该转换思路。上面这种思路的问题所在就是除法,那么,现在就要避免除法。设$dp2[i]$表示除去以节点$i$为根的子树后剩余的树中的修路方式。如图所示,红框中的树上所有的修路方式就是$dp2[i]$。
有了$dp2$以后,就可以得到:$dp2[j] = (dp2[i] * \prod\limits_{k}(dp[k] + 1) + 1) \% (10^9 + 7), ans[j] = dp1[j] * dp2[j]$。其中,$j$为$i$的儿子节点,$k$为$j$的所有兄弟节点。而计算$\prod\limits_{k}(dp[k] + 1)$,需要预处理,否则会TLE在“星型树”的样例上。
预处理出如下两个信息:
(1)$vector<int> pre[MAXN]$。其中,$pre[i]$表示节点$i$的儿子节点的$dp$前缀积;即:$pre[i][j]$表示节点$i$的编号从$0$到$j$的儿子节点的$dp$前缀积;
(2)$vector<int> suf[MAXN]$。其中,$suf[i]$表示节点$i$的儿子节点的$dp$后缀积。即:$suf[i][j]$表示节点$i$的编号从$j$到$suf[i].size()-1$的儿子节点的$dp$后缀积;
因为出现了“前缀”和“后缀”的概念,所以,对于每个节点$i$而言,都需要把他的所有子节点按顺序编号。因此,树的存储结构不能再使用链式前向星的方式,而应该写成邻接表的形式。而且,要注意的是,建树时,不要建成双向图(树是特殊的图^_^),因为要对子节点编号。如果父节点又是子节点的子节点,那就乱了。
然后,对于节点$x$的第$j$子节点$y$而言,有\[ans[y]=(dp[y] * dp2[x] * (pre[x][j-1] * suf[x][j+1]) + 1) \% (10^9 + 7)\] 这个地方要注意这些下标的意义:$x$和$y$是树中节点的编号,总根编号为$1$。$j$是节点$y$在节点$x$的所有子节点中的位置。如果节点$x$有三个节点,$y$是$x$的第$2$个节点,那么,$j$为$1$(因为下标从$0$开始嘛)。
这里递推式比较多,使用LaTeX编辑时容易出现小错误,如发现,还请在评论区多多指正!
四、源代码
#include<bits/stdc++.h>
using namespace std;
#define pb(x) push_back(x)
#define MAXN 200010
#define MOD 1000000007
typedef long long LL;
vector<int> tree[MAXN], pre[MAXN], suf[MAXN];
LL n, dp1[MAXN], dp2[MAXN];
void dfs0(int root) {
, sz = tree[root].size(); i < sz; ++i) {
int to = tree[root][i];
dfs0(to);
dp1[root] = (dp1[root] * ((dp1[to] + ) % MOD)) % MOD;
)pre[root].pb(pre[root].back() * (dp1[to] + ) % MOD);
) % MOD);
}
; i >= ;--i){
int to = tree[root][i];
)suf[root].pb(suf[root].back() * (dp1[to] + ) % MOD);
) % MOD);
}
reverse(suf[root].begin(), suf[root].end());
}
void dfs1(int root) {
, sz = tree[root].size(); i < sz; ++i) {
int to = tree[root][i];
LL ps = i == ? : pre[root][i - ], ss = i == sz - ? : suf[root][i + ];
dp2[to] = ((dp2[root] * ps % MOD) * ss + ) % MOD;
dfs1(to);
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
#endif // ONLINE_JUDGE
int from;
scanf("%I64d", &n);
; i <= n; ++i)dp1[i] = , dp2[i] = ;
; i <= n; ++i) {
scanf("%d", &from);
tree[from].pb(i);
}
dfs0();
dfs1();
; i <= n; ++i)printf("%I64d%c", dp1[i] * dp2[i] % MOD, i == n ? '\n' : ' ');
;
}
DP系列——树形DP(Codeforces543D-Road Improvement)的更多相关文章
- [DP之树形DP]
树形dp出了应该还是比计数dp要简单的 因为很好可以看出来 常用的是一个F记录子树内的 一个G记录子树外的 还有一种就是有环的做过要用状压搞一下 不说这么多直接上例题 [HAOI2015]T1 经典的 ...
- [Codeforces543D]Road Improvement
Problem 刚开始每条边都是坏的,现在要选取一个点使得其他点到这个点的路径上最多只有一条坏路,问至少要修好多少条边 Solution 如果以1为根,那么是个简单的树形DP 设根从u转移到v,那么u ...
- CF123E Maze(期望dp,树形dp,式子)
题目大意: 给你一棵树,边权都是1,每一个点有一个是起点的概率和一个是终点的概率,你将以起点为根,开始在树上随机dfs,每到一个点,就会将他的所有儿子随机打乱成序列,然后按照那个随机顺序走完,直到走到 ...
- 【转】【DP_树形DP专辑】【9月9最新更新】【from zeroclock's blog】
树,一种十分优美的数据结构,因为它本身就具有的递归性,所以它和子树见能相互传递很多信息,还因为它作为被限制的图在上面可进行的操作更多,所以各种用于不同地方的树都出现了,二叉树.三叉树.静态搜索树.AV ...
- 【DP_树形DP专题】题单总结
转载自 http://blog.csdn.net/woshi250hua/article/details/7644959#t2 题单:http://vjudge.net/contest/123963# ...
- 树形动态规划(树形DP)入门问题—初探 & 训练
树形DP入门 poj 2342 Anniversary party 先来个题入门一下~ 题意: 某公司要举办一次晚会,但是为了使得晚会的气氛更加活跃,每个参加晚会的人都不希望在晚会中见到他的直接上 ...
- [P2996][USACO10NOV]拜访奶牛Visiting Cows (树形DP)
之前写在洛谷,结果没保存,作废…… 听说考前写题解RP++哦 思路 很容易想到是 树形DP 如果树形DP不知道是什么的话推荐百度一下 我在这里用vector储存边 设状态f[i][0]为i点不访问,f ...
- 树形DP(超详细!!!)
一.概念 1.什么是树型动态规划 树型动态规划就是在“树”的数据结构上的动态规划,平时作的动态规划都是线性的或者是建立在图上的,线性的动态规划有二种方向既向前和向后,相应的线性的动态规划有二种方法既顺 ...
- Codeforces1223E. Paint the Tree(树形dp)
题目链接:传送门 题目大意: 给出节点数为n的一棵带权树,和每个点的最大染色数k.一条边的权重w能产生价值w的条件是,这条边的两端的点至少有一个颜色相同.颜色种类数无限,但每种只能使用两次,问能产生的 ...
随机推荐
- 学习mybatis-3 step by step 篇一
一.搭建简单mybatis-3环境(详细的中文文档) 集成开发环境:IDEA 项目:maven + mybatis-3 1.创建maven结构项目 含简单,如下图: 下一步后,填写groupid和ar ...
- Numpy 练习题
1. 使用循环和向量化两种不同的方法来计算 100 以内的质数之和. 先定义个判断质数的函数.ps:纯手工打造,原生态,哈哈. def checkprime(x): if x<=1: retur ...
- json.dump()和json.load()
import json,time # save data to json file def store(data): with open('data.json', 'w') as fw: # 将字典转 ...
- git 重写历史
重写最后一次提交的commit git commit --amend 修改多个历史 git rebase -i HEAD~3 命令执行后结果如下: pick f7f3f6d changed my na ...
- 牛客网——E进阶吧阶乘
链接:https://www.nowcoder.net/acm/contest/75/E来源:牛客网 时间限制:C/C++ 3秒,其他语言6秒 空间限制:C/C++ 32768K,其他语言65536K ...
- vue.js利用vue.router创建前端路由
node.js方式: 利用node.js安装vue-router模块 cnpm install vue-router 安装完成后我们引入这个模板! 下载vue-router利用script引入方式: ...
- hdu 3682 10 杭州 现场 C - To Be an Dream Architect 简单容斥 难度:1
C - To Be an Dream Architect Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d &a ...
- Java Mongodbjar包下载网址
http://mongodb.github.io/mongo-java-driver/
- Terminal shortcuts
<backspace> 删除 <ctrl+l> 清空屏幕, 相当于clear <ctrl+e> 光标跳至命令结尾 <ctrl+a> 光标跳至命令开始 & ...
- 关于CMD中延迟环境变量嵌套的实现方法
在我昨天做的一个bat中(自动按日期重命名文件名)涉及到这方面的问题 以前涉及到这里时就想别的办法替代过去,今天好好扒出来说说: 实现变量嵌套的2种方法: 1,使用call实现变量嵌套 变量嵌套:即在 ...