题目大概说给一棵树,树的边一开始都是损坏的,要修复一些边,修复完后要满足各个点到根的路径上最多只有一条坏的边,现在以各个点为根分别求出修复边的方案数,其结果模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 + 乘法逆元)的更多相关文章

  1. Codeforces 543D. Road Improvement (树dp + 乘法逆元)

    题目链接:http://codeforces.com/contest/543/problem/D 给你一棵树,初始所有的边都是坏的,要你修复若干边.指定一个root,所有的点到root最多只有一个坏边 ...

  2. Codeforces 543D Road Improvement(DP)

    题目链接 Solution 比较明显的树形DP模型. 首先可以先用一次DFS求出以1为根时,sum[i](以i为子树的根时,满足要求的子树的个数). 考虑将根从i变换到它的儿子j时,sum[i]产生的 ...

  3. Codeforces Round #302 (Div. 1) D - Road Improvement 树形dp

    D - Road Improvemen 思路:0没有逆元!!!! 不能直接除,要求前缀积和后缀积!!! #include<bits/stdc++.h> #define LL long lo ...

  4. Codeforces 543D Road Improvement

    http://codeforces.com/contest/543/problem/D 题意: 给定n个点的树 问: 一开始全是黑边,对于以i为根时,把树边白染色,使得任意点走到根的路径上不超过一条黑 ...

  5. codeforces 212E IT Restaurants(树形dp+背包思想)

    题目链接:http://codeforces.com/problemset/problem/212/E 题目大意:给你一个无向树,现在用两种颜色去给这颗树上的节点染色.用(a,b)表示两种颜色分别染的 ...

  6. Codeforces 123E Maze(树形DP+期望)

    [题目链接] http://codeforces.com/problemset/problem/123/E [题目大意] 给出一棵,给出从每个点出发的概率和以每个点为终点的概率,求出每次按照dfs序从 ...

  7. BZOJ 1004: [HNOI2008]Cards( 置换群 + burnside引理 + 背包dp + 乘法逆元 )

    题意保证了是一个置换群. 根据burnside引理, 答案为Σc(f) / (M+1). c(f)表示置换f的不动点数, 而题目限制了颜色的数量, 所以还得满足题目, 用背包dp来计算.dp(x,i, ...

  8. codeforces 709E E. Centroids(树形dp)

    题目链接: E. Centroids time limit per test 4 seconds memory limit per test 512 megabytes input standard ...

  9. CodeForces 77C Beavermuncher-0xFF (树形dp)

    不错的树形dp.一个结点能走多次,树形的最大特点是到达后继的路径是唯一的,那个如果一个结点无法往子结点走,那么子结点就不用考虑了. 有的结点不能走完它的子结点,而有的可能走完他的子节点以后还会剩下一些 ...

随机推荐

  1. 关于 UICollectionViewCell 的一些陷阱

    如果直接使用 UICollectionViewCell 的自带属性 selected 来自定义一些样式,如: - (void)setSelected:(BOOL)selected { [super s ...

  2. Android接口传递Json数组的处理方式

    public static XTResult<Void> addTravel(String uuid, String travelName, String travelId, String ...

  3. iOS 百度地图坐标标注

    注:由于iOS9改用更安全的https,为了能够在iOS9中正常使用地图SDK,请在"Info.plist"中进行如下配置,否则影响SDK的使用. <key>NSApp ...

  4. Swift - 多行文本输入框(UITextView)

    1,多行文本控件的创建 1 2 3 4 let textview = UITextView(frame:CGRect(x:10, y:100, width:200, height:100)) text ...

  5. hdu 2020

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2020 思路:优先队列水过priority_queue #include <cstdio> ...

  6. JavaScript基础——处理字符串

    String对象是迄今为止在JavaScript中最常用的对象.在你定义一个字符串数据类型的变量的任何时候,JavaScript就自定为你创建一个String对象.例如: var myStr = &q ...

  7. MVC缓存02,使用数据层缓存,添加或修改时让缓存失效

    在"MVC缓存01,使用控制器缓存或数据层缓存"中,在数据层中可以设置缓存的有效时间.但这个还不够"智能",常常希望在编辑或创建的时候使缓存失效,加载新的数据. ...

  8. Java系列笔记(3) - Java 内存区域和GC机制

    目录 Java垃圾回收概况 Java内存区域 Java对象的访问方式 Java内存分配机制 Java GC机制 垃圾收集器 Java垃圾回收概况 Java GC(Garbage Collection, ...

  9. Delphi运算符总结

    分类 运算符 操作 操作数 结果类型 范例 算术运算符(加法.减法和乘法运算符的结果为参加运算的两个数据中的精度高的类型) + 加 整数,实数 整数,实数 X + Y - 减 整数,实数 整数,实数 ...

  10. SQL索引及视图常用语法

    ALTER TABLE department ADD INDEX dept_name_idx (name); SHOW INDEX FROM department \G ALTER TABLE dep ...