Codeforces 543D Road Improvement(树形DP + 乘法逆元)
题目大概说给一棵树,树的边一开始都是损坏的,要修复一些边,修复完后要满足各个点到根的路径上最多只有一条坏的边,现在以各个点为根分别求出修复边的方案数,其结果模1000000007。
不难联想到这题和HDU2196是一种类型的树形DP,因为它们都要分别求各个点的答案。然后解法也不难想:
- dp0[u]表示只考虑以u结点为根的子树的方案数
- dp1[u]表示u结点往上走,倒过来,以它父亲为根那部分的方案数
有了这两部分的结果,对于各个点u的答案就是dp0[u]*(dp1[u]+1)。这两部分求法如下,画画图比较好想:
- 首先求出dp0,这个转移是:dp0[u]=∏(dp0[v]+1)(v是u的孩子),就是对于每个孩子为根的子树的情况总数的乘积,而其中每个孩子的情况总数还要加上一个父亲到孩子之间的边不修复、孩子的子树的边全部修复的情况。
- 然后求出dp1,转移:求dp1[v],u是v的父亲,dp1[v]=dp0[u]/dp0[v]*(dp1[u]+1)。
- 现在问题来了,求dp0[u]/dp0[v],注意到结果模1000000007是一个质数,一开始我用乘法逆元WA了,因为虽然1000000007是质数,但1000000007的倍数不与1000000007互质,模1000000007结果是0,这样就出问题了!
- 本来我想改用线段树做,不过队友提醒说可以分情况讨论,如果不存在与1000000007不互质的数直接逆元搞,存在两个以上不与1000000007互质的数那结果就是0,一个的话。。。。。我就不多说了。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 222222
struct Edge{
int v,next;
}edge[MAXN<<];
int NE,head[MAXN];
void addEdge(int u,int v){
edge[NE].v=v; edge[NE].next=head[u];
head[u]=NE++;
}
long long d[][MAXN];
long long ine(long long a){
long long res=;
int n=-;
while(n){
if(n&){
res*=a;
res%=;
}
a*=a;
a%=;
n>>=;
}
return res;
}
void dp0(int u,int fa){
long long res=;
for(int i=head[u]; i!=-; i=edge[i].next){
int v=edge[i].v;
if(v==fa) continue;
dp0(v,u);
res*=d[][v]+;
res%=;
}
d[][u]=res;
}
void dp1(int u,int fa){
int cnt=;
long long tot=;
for(int i=head[u]; i!=-; i=edge[i].next){
int v=edge[i].v;
if(v==fa) continue;
if((d[][v]+)%==) ++cnt;
else{
tot*=d[][v]+;
tot%=;
}
}
for(int i=head[u]; i!=-; i=edge[i].next){
int v=edge[i].v;
if(v==fa) continue;
if(cnt){
if((d[][v]+)%== && cnt==){
d[][v]=tot;
}else d[][v]=;
}else{
d[][v]=d[][u]*ine((d[][v]+)%);
d[][v]%=;
}
d[][v]*=d[][u]+;
d[][v]%=;
dp1(v,u);
}
}
int main(){
memset(head,-,sizeof(head));
int n,a;
scanf("%d",&n);
for(int i=; i<=n; ++i){
scanf("%d",&a);
addEdge(a,i);
addEdge(i,a);
}
dp0(,);
dp1(,);
for(int i=; i<=n; ++i){
printf("%lld ",d[][i]*(d[][i]+)%);
}
return ;
}
Codeforces 543D Road Improvement(树形DP + 乘法逆元)的更多相关文章
- Codeforces 543D. Road Improvement (树dp + 乘法逆元)
题目链接:http://codeforces.com/contest/543/problem/D 给你一棵树,初始所有的边都是坏的,要你修复若干边.指定一个root,所有的点到root最多只有一个坏边 ...
- Codeforces 543D Road Improvement(DP)
题目链接 Solution 比较明显的树形DP模型. 首先可以先用一次DFS求出以1为根时,sum[i](以i为子树的根时,满足要求的子树的个数). 考虑将根从i变换到它的儿子j时,sum[i]产生的 ...
- Codeforces Round #302 (Div. 1) D - Road Improvement 树形dp
D - Road Improvemen 思路:0没有逆元!!!! 不能直接除,要求前缀积和后缀积!!! #include<bits/stdc++.h> #define LL long lo ...
- Codeforces 543D Road Improvement
http://codeforces.com/contest/543/problem/D 题意: 给定n个点的树 问: 一开始全是黑边,对于以i为根时,把树边白染色,使得任意点走到根的路径上不超过一条黑 ...
- codeforces 212E IT Restaurants(树形dp+背包思想)
题目链接:http://codeforces.com/problemset/problem/212/E 题目大意:给你一个无向树,现在用两种颜色去给这颗树上的节点染色.用(a,b)表示两种颜色分别染的 ...
- Codeforces 123E Maze(树形DP+期望)
[题目链接] http://codeforces.com/problemset/problem/123/E [题目大意] 给出一棵,给出从每个点出发的概率和以每个点为终点的概率,求出每次按照dfs序从 ...
- BZOJ 1004: [HNOI2008]Cards( 置换群 + burnside引理 + 背包dp + 乘法逆元 )
题意保证了是一个置换群. 根据burnside引理, 答案为Σc(f) / (M+1). c(f)表示置换f的不动点数, 而题目限制了颜色的数量, 所以还得满足题目, 用背包dp来计算.dp(x,i, ...
- codeforces 709E E. Centroids(树形dp)
题目链接: E. Centroids time limit per test 4 seconds memory limit per test 512 megabytes input standard ...
- CodeForces 77C Beavermuncher-0xFF (树形dp)
不错的树形dp.一个结点能走多次,树形的最大特点是到达后继的路径是唯一的,那个如果一个结点无法往子结点走,那么子结点就不用考虑了. 有的结点不能走完它的子结点,而有的可能走完他的子节点以后还会剩下一些 ...
随机推荐
- Hadoop组件之-HDFS(HA实现细节)
NameNode 高可用整体架构概述 在 Hadoop 1.0 时代,Hadoop 的两大核心组件 HDFS NameNode 和 JobTracker 都存在着单点问题,这其中以 NameNode ...
- Android Tab -- 使用ViewPager、Fragment、FragmentPagerAdapter来实现
原文地址:http://blog.csdn.net/crazy1235/article/details/42678877 效果:滑动切换:点击标签切换. 代码:https://github.com/l ...
- WPF布局
1.Canvas 布局控件 Canvas面板是最轻量级的布局容器,它不会自动调整内部元素的排列和大小,不指定元素位置,元素将默认显示在画布的左上方.Canvas主要用来画图.Canvas默认不会自动裁 ...
- Pyqt 获取windows系统中已安装软件列表
开始之前的基础知识 1. 获取软件列表 在Python的标准库中,_winreg可以操作Windows的注册表.获取已经安装的软件列表一般是读去windows的注册表: SOFTWARE\Micros ...
- 使用git进行团队合作开发
1.git 和 svn 的差异 git和svn 最大的差异在于git是分布式的管理方式而svn是集中式的管理方式.如果不习惯用代码管理工具,可能比较难理解分布式管理和集中式管理的概念.下面介绍两种工具 ...
- golang heap container balance request
package mainimport ( "container/heap" "fmt" "log" "math/rand" ...
- JavaScript - 基本概念
相等操作符 == 和 != 是先转换再比较 === 和 !== 是直接比较,不经过转换 中文翻译上来说叫做相等和全等.类型转换简单的概括就是高级转低级,比如说布尔字符串转数字,对象取值再转.相等比较有 ...
- python生成RSS(PyRSS2Gen)
既然能够用python解析rss,那么也顺带研究下生成rss. 其实很简单,只是生成一个比较特殊点的xml文档而已. 这里我使用了PyRss2Gen,用法很简单,看代码就知道了,如下: import ...
- [Tools] 设置surface上的VPN
[背景] 继续前对机器进行配置安装,这次是VPN在win8上的设置,又跟xp不一样,看来要慢慢适应win8的日子,呵呵 [开工] 首先按照原先在win xp上的步骤一步步来配置 选择connect t ...
- 使用VS把ASP.NET 5的应用发布到Linux的Docker上
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:我相信未来应用程序的部署模式首选一定会是Docker,所以.NET社区的朋友也不应该忽 ...