Evensgn 剪树枝

题目

繁华中学有一棵苹果树。苹果树有 n 个节点(也就是苹果),n − 1 条边(也就

是树枝)。调皮的 Evensgn 爬到苹果树上。他发现这棵苹果树上的苹果有两种:一

种是黑苹果,一种是红苹果。Evensgn 想要剪掉 k 条树枝,将整棵树分成 k + 1 个

部分。他想要保证每个部分里面有且仅有一个黑苹果。请问他一共有多少种剪树枝

的方案?

INPUT

第一行一个数字 n,表示苹果树的节点(苹果)个数。

第二行一共 n − 1 个数字 p0, p1, p2, p3, ..., pn−2,pi 表示第 i + 1 个节点和 pi 节

点之间有一条边。注意,点的编号是 0 到 n − 1。

第三行一共 n 个数字 x0, x1, x2, x3, ..., xn−1。如果 xi 是 1,表示 i 号节点是黑

苹果;如果 xi 是 0,表示 i 号节点是红苹果。

OUTPUT

输出一个数字,表示总方案数。答案对$10^{9}+7$取模

SAMPLE

INPUT

10

0 1 2 1 4 4 4 0 8

0 0 0 1 0 1 1 0 0 1

OUTPUT

27

解题报告

考试就没咋打这题,于是就骗了十分

正解:

树规

我们设$has[i]$表示节点$i$及其子树带一个黑苹果对父节点产生的方案数贡献

$no[i]$表示节点$i$及其子树不带黑苹果对父节点产生的方案数贡献

我们从叶节点开始讨论

当该叶子为红苹果时,显然无法对父节点产生带黑苹果的方案数贡献,而且它是叶子节点,所以可以对父节点产生$1$的不带黑苹果的方案数贡献,故:

$$has[i]=1,no[i]=0$$

当该节点为黑苹果时,显然可以对父节点产生带黑苹果的方案数贡献,而且它是叶子节点,所以可以对父节点产生$1$的带一个黑苹果的方案数贡献。我们再考虑,当我们砍断它与父节点之间的边时,它也可以对父节点产生$1$的不带黑苹果的方案数贡献,故:

$$has[i]=1,no[i]=1$$

当该节点不为叶子节点时:

假如该节点为黑苹果,那么显然,它的子树无法对他产生带一个黑苹果的方案数贡献(我们先假设它的子树可以,那么,以该节点为根节点的子树就一定有两个或以上的黑苹果,显然是不合法的方案,故舍去)

所以,它的子树对它只能产生不带黑苹果的方案数贡献。

由乘法原理:

$$\prod^{}_{j\in son[i]}no[j]$$

并且,由与黑苹果叶子节点同样的推理方式,我们可以得到:

$$no[i]=has[i]$$

原因仍然是砍断它与父节点之间的边所能造成的贡献

假如该节点为红苹果,我们先考虑$has[i]$,因为它是一个红苹果,所以它自己不能产生对父节点带一个黑苹果的贡献,所以,我们要对子树的$has[j]$进行处理,我们考虑,当该节点的某一棵子树产生了一个黑苹果的贡献时,其它子树就不能再贡献黑苹果了,所以,我们枚举每一棵子树的$has$值,与其它子树的$no$值相乘(同样是乘法原理)(注意这里,实际上有赌数据的成分,假如数据给个菊花树,瞬间爆炸,菊花树:除了根节点,其他点深度均为1,即根节点为所有其他点的父节点的树的简称,然而还是跑的贼快2333),再取和即为其值,即:

$$has[i]=\sum ^{}_{j\in son[i]}(has[i]\times \prod^{}_{k\in son[i] k\neq j}no[k])$$

再考虑$no$值就很简单了,首先,假如它的子树都不产生黑苹果贡献,那么它自然不可以对父节点产生贡献,所以首先取个累乘,接着,假如它的子树产生了黑苹果贡献,只要我们砍掉它与父节点之间的边,它仍然可以产生该贡献,所以:

$$no[i]=\prod^{}_{j\in son[i]}no[j]+has[i]$$

代码:

 #include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
inline int read(){
int sum();
char ch(getchar());
for(;ch<''||ch>'';ch=getchar());
for(;ch>=''&&ch<='';sum=sum*+(ch^),ch=getchar());
return sum;
}
const int mod=;
struct edge{
int e,n;
}a[];
int pre[],tot;
inline void insert(int s,int e){
a[++tot].e=e;
a[tot].n=pre[s];
pre[s]=tot;
}
typedef long long L;
int fa[];
int n;
int w[];
L has[],no[];
inline void dfs(int u){
bool flag(false);
for(int i=pre[u];i!=-;i=a[i].n){
int e(a[i].e);
if(e!=fa[u]){
fa[e]=u;
flag=true;
dfs(e);
}
}
if(!flag){
if(w[u]==){
has[u]=;
no[u]=;
return;
}
has[u]=no[u]=;
return;
}
if(w[u]==){
has[u]=no[u]=;
for(int i=pre[u];i!=-;i=a[i].n){
int e(a[i].e);
if(e!=fa[u])
has[u]=no[u]=(no[u]*no[e])%mod;
}
return;
}
has[u]=;
for(int i=pre[u];i!=-;i=a[i].n){
int e1(a[i].e);
if(e1==fa[u])
continue;
L tmp(has[e1]);
for(int j=pre[u];j!=-;j=a[j].n){
int e2(a[j].e);
if(e1==e2||e2==fa[u])
continue;
tmp=(tmp*no[e2])%mod;
}
has[u]=(has[u]+tmp)%mod;
}
no[u]=;
for(int i=pre[u];i!=-;i=a[i].n){
int e(a[i].e);
if(e==fa[u])
continue;
no[u]=(no[u]*no[e])%mod;
}
no[u]=(no[u]+has[u])%mod;
}
int main(){
memset(fa,-,sizeof(fa));
memset(pre,-,sizeof(pre));
n=read();
for(int i=;i<n;i++){
int x(read());
insert(x,i),insert(i,x);
}
for(int i=;i<n;i++)
w[i]=read();
dfs();
printf("%lld",has[]);
}

[繁华模拟赛]Evensgn 剪树枝的更多相关文章

  1. 繁华模拟赛 Evensgn剪树枝

    #include<iostream> #include<cstdio> #include<string> #include<cstring> #incl ...

  2. 繁华模拟赛 Evensgn与字符矩阵

    #include<iostream> #include<cstdio> #include<string> #include<cstring> #incl ...

  3. 繁华模拟赛 Evensgn玩序列

    #include<iostream> #include<cstdio> #include<string> #include<cstring> #incl ...

  4. 繁华模拟赛 Evensgn的债务

    #include<iostream> #include<cstdio> #include<string> #include<cstring> #incl ...

  5. 【NOIP 模拟赛】Evensgn 剪树枝 树形dp

    由于树规做的少所以即使我考试想出来正确的状态也不会转移. 一般dp的转移不那么繁杂(除了插头.....),即使多那也是清晰明了的,而且按照树规的一般思路,我们是从下到上的,所以我们要尽量简洁地从儿子那 ...

  6. 繁华模拟赛day8 牛栏

    /* 标称并没有用到题解中提到的那种奇妙的性质,我们可以证明,正常从1开始走的话,需要T次,如何使这个次数减小?题解中提到一个办法,有一步小于n/t,我们考虑这一步,如果把它匀到左右两步中,则可以减小 ...

  7. 繁华模拟赛day8 字典序

    /* 这个题要我们求一个字典序,字符串给出的顺序,会对字母的字典序前后相对顺序进行限定,如何用来表示这种限定,我们注意到这种一个之后接着一个,只有先输出他前面的才能输出他,很明显就是拓扑排序,最小方案 ...

  8. 繁华模拟赛day8 科技树

    /* 贪心,很明显是越容易升级的越先升级 */ #include<iostream> #include<cstdio> #include<string> #incl ...

  9. 繁华模拟赛 Vicent坐电梯

    /*n<=5000­这样就不能用O(n)的转移了,而是要用O(1)的转移.­注意我们每次的转移都来自一个连续的区间,而且我们是求和­区间求和?­前缀和!­令sum[step][i]表示f[ste ...

随机推荐

  1. Java I/O 的工作机制浅析

    I/O 问题可以说是当今互联网 Web 应用中所面临的主要问题之一,因为当前在这个海量数据时代,数据在网络中随处流动.这个流动的过程中都涉及到 I/O 问题,可以说大部分 Web 应用系统的瓶颈都是 ...

  2. FPC报价模块配置 UpdateCommand影响了预期 1 条记录中的 0 条 解决办法

    今天在增加P4厂 FPC报价模块配置,增加刚挠信息节点,在保存时报错:UpdateCommand影响了预期 1 条记录中的 0 保存时使用:SqlDataAdapter批量更新DataTable,怎么 ...

  3. E20170626-hm

    authenticate   vt. 认证,证明是真实的.可靠的或有效的; 鉴定,使生效; author   n. 作者; 著作家; 创造者; 发起人;

  4. 禁用backspace网页回退功能

    <script language="JavaScript">document.onkeydown = check;function check(e) { var cod ...

  5. ZOJ3714JavaBeans

    #!/usr/bin/env python # encoding: utf-8 t = int(raw_input()) for i in range(t): n,k = [int(x) for x ...

  6. CF 436D 最小生成树

    设一个开头的虚节点,然后建稠密图,O(n^2).使用prim.O(n^2),保存方案,没什么好说的. #include <string.h> #include <stdio.h> ...

  7. 关于BUG

    1.BUG的理解 2.提高BUG report的技巧

  8. Java系列学习(一)-JDK下载与安装

    1.Java语言平台版本 J2SE:Java 2 Platform Standard Edition,java平台标准版 J2ME:Java 2 Platform Micro Edition,java ...

  9. 将class类对象转化成json的数据格式

    直接上代码: JSONObject的的使用需要导入json-lib-2.4-jdk15.jar包,下载地址:http://mvnrepository.com/artifact/net.sf.json- ...

  10. Elasticsearch_Lucene基础

    Lucene基本概念 文档(document):索引与搜索的主要载体,它包含一个或多个字段,存放将要写入索引的或将从索引搜索出来的数据. 字段(field):文档的一个片段,它包含字段的名称和字段的内 ...