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. 【POJ 1723】 SOLDIERS

    [题目链接] http://poj.org/problem?id=1723 [算法] 中位数 [代码] #include <algorithm> #include <bitset&g ...

  2. Notepad++ - 通过语言格式设置自定义语法高亮颜色

    http://blog.csdn.net/onceing/article/details/51554399 Global Styles Indent guideline style  缩进参考线的颜色 ...

  3. Dsp和ARM的区别

    有一次上课老师在将ARM的时候说到了Dsp. Dsp(Digital Signal Process),数字信号处理技术,而Dsp芯片和ARM的结构也有很多相似之处.比如有流水线.采用哈佛结构(早期的A ...

  4. max_allowed_packet设置问题

    最近在运行的项目出现了一个线上事故,有人反映商城的东西下不了单了,到后台看了一下,果然报了一个错 Cause: com.mysql.jdbc.PacketTooBigException: Packet ...

  5. Java Web框架前景浅析

    基于三(多)层架构模式,典型WEB系统的总体架构如下图所示: 在上述分层架构中,整个应用被划分为两大部分: 客户端:基于浏览器提供信息展现.用户交互等功能.所采用的技术主要有:HTML/HTML5.J ...

  6. html5——地理位置

    获取地理位置 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UT ...

  7. html5——颜色

    CSS2 1.opacity,可以设置透明度,但是父盒子设置了透明度会影响子盒子 CC3 1.transparent属性,但是不可改变透明值 2.rgba():r--red g--green b--b ...

  8. JS——事件冒泡与捕获

    事件冒泡与事件捕获 1.冒泡:addEventListener("click",fn,false)或者addEventListener("click",fn): ...

  9. 四次挥手与tcp标志位

    鉴于tcp的标志位可以同时置位,在相应端无数据传输时,四次握手可以用三次报文完成.

  10. Discuz 首页图文列表实现

    <div id="shoucang"> <!--{eval $list_count=0;}--> <!--{loop $threadlist $thr ...