首页 > 代码库 > [繁华模拟赛]Evensgn 剪树枝

[繁华模拟赛]Evensgn 剪树枝

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]$$

代码:

技术分享
 1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 inline int read(){ 6     int sum(0); 7     char ch(getchar()); 8     for(;ch<0||ch>9;ch=getchar()); 9     for(;ch>=0&&ch<=9;sum=sum*10+(ch^48),ch=getchar());10     return sum;11 }12 const int mod=1000000007;13 struct edge{14     int e,n;15 }a[200005];16 int pre[100005],tot;17 inline void insert(int s,int e){18     a[++tot].e=e;19     a[tot].n=pre[s];20     pre[s]=tot;21 }22 typedef long long L;23 int fa[100005];24 int n;25 int w[100005];26 L has[100005],no[100005];27 inline void dfs(int u){28     bool flag(false);29     for(int i=pre[u];i!=-1;i=a[i].n){30         int e(a[i].e);31         if(e!=fa[u]){32             fa[e]=u;33             flag=true;34             dfs(e);35         }36     }37     if(!flag){38         if(w[u]==0){39             has[u]=0;40             no[u]=1;41             return;42         }43         has[u]=no[u]=1;44         return;45     }46     if(w[u]==1){47         has[u]=no[u]=1;48         for(int i=pre[u];i!=-1;i=a[i].n){49             int e(a[i].e);50             if(e!=fa[u])51                 has[u]=no[u]=(no[u]*no[e])%mod;52         }53         return;54     }55     has[u]=0;56     for(int i=pre[u];i!=-1;i=a[i].n){57         int e1(a[i].e);58         if(e1==fa[u])59             continue;60         L tmp(has[e1]);61         for(int j=pre[u];j!=-1;j=a[j].n){62             int e2(a[j].e);63             if(e1==e2||e2==fa[u])64                 continue;65             tmp=(tmp*no[e2])%mod;66         }67         has[u]=(has[u]+tmp)%mod;68     }69     no[u]=1;70     for(int i=pre[u];i!=-1;i=a[i].n){71         int e(a[i].e);72         if(e==fa[u])73             continue;74         no[u]=(no[u]*no[e])%mod;75     }76     no[u]=(no[u]+has[u])%mod;77 }78 int main(){79     memset(fa,-1,sizeof(fa));80     memset(pre,-1,sizeof(pre));81     n=read();82     for(int i=1;i<n;i++){83         int x(read());84         insert(x,i),insert(i,x);85     }86     for(int i=0;i<n;i++)87         w[i]=read();88     dfs(0);89     printf("%lld",has[0]);90 }
View Code

 

[繁华模拟赛]Evensgn 剪树枝