[繁华模拟赛]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]$$
代码:
#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 剪树枝的更多相关文章
- 繁华模拟赛 Evensgn剪树枝
#include<iostream> #include<cstdio> #include<string> #include<cstring> #incl ...
- 繁华模拟赛 Evensgn与字符矩阵
#include<iostream> #include<cstdio> #include<string> #include<cstring> #incl ...
- 繁华模拟赛 Evensgn玩序列
#include<iostream> #include<cstdio> #include<string> #include<cstring> #incl ...
- 繁华模拟赛 Evensgn的债务
#include<iostream> #include<cstdio> #include<string> #include<cstring> #incl ...
- 【NOIP 模拟赛】Evensgn 剪树枝 树形dp
由于树规做的少所以即使我考试想出来正确的状态也不会转移. 一般dp的转移不那么繁杂(除了插头.....),即使多那也是清晰明了的,而且按照树规的一般思路,我们是从下到上的,所以我们要尽量简洁地从儿子那 ...
- 繁华模拟赛day8 牛栏
/* 标称并没有用到题解中提到的那种奇妙的性质,我们可以证明,正常从1开始走的话,需要T次,如何使这个次数减小?题解中提到一个办法,有一步小于n/t,我们考虑这一步,如果把它匀到左右两步中,则可以减小 ...
- 繁华模拟赛day8 字典序
/* 这个题要我们求一个字典序,字符串给出的顺序,会对字母的字典序前后相对顺序进行限定,如何用来表示这种限定,我们注意到这种一个之后接着一个,只有先输出他前面的才能输出他,很明显就是拓扑排序,最小方案 ...
- 繁华模拟赛day8 科技树
/* 贪心,很明显是越容易升级的越先升级 */ #include<iostream> #include<cstdio> #include<string> #incl ...
- 繁华模拟赛 Vicent坐电梯
/*n<=5000这样就不能用O(n)的转移了,而是要用O(1)的转移.注意我们每次的转移都来自一个连续的区间,而且我们是求和区间求和?前缀和!令sum[step][i]表示f[ste ...
随机推荐
- [Apple开发者帐户帮助]九、参考(1)证书类型
该证书类型有助于开发者帐户和Xcode的标识证书. 类型 目的 APNs Auth Key 生成服务器端令牌,以替代通知请求的证书. Apple推送服务 在通知服务和APN之间建立连接,以向您的应用提 ...
- QT 制作串口调试小助手----(小白篇)
一.成品图展示 简介:因zigbee实验,制作一个相对简易版的上位机,接收来自zigbee无线传感采集的温湿度.光照等数据. 并且将数据部分描绘成实时动态折线统计图. 二.主要功能介绍 主要使用QT自 ...
- Eclipse 添加 YAML插件
官网:https://github.com/oyse/yedit 离线版本:(链接: https://pan.baidu.com/s/1PJzkS1tI-VigZvfbYXUh9A 密码: gfep) ...
- Appium Appium 链接夜神模拟器
在此之前,已经安装Appium,参考第一部分在 Windows7 搭建 Appium (一) https://testerhome.com/topics/8004 第一步安装Android开发环境 下 ...
- 【LeetCode】-- 260. Single Number III
问题描述: https://leetcode.com/problems/single-number-iii/ 在一个数组里面,只有两个元素仅出现过1次,其余都出现过两次.找出出现仅一次的那两个(a, ...
- iOS动画——CoreAnimation
CoreAnimation在我之前的UIKit动画里面简单的提了一句CoreAnimation动画,其实大家别看它类库名种有个animation,实际上animation在这个库中只占有很小的地位. ...
- python算数运算符
---恢复内容开始--- 加减乘除 >>> 1+1 2 >>> 4-2 2 >>> 2*5 10 >>> 8/2 4.0 > ...
- Android 6.0 如何添加完整的系统服务(app-framework-kernel)
最近学习了如何在Android 6.0上添加一个系统服务,APP如何通过新增的系统服务访问底层驱动.在这学习过程中,收获颇多,并结合学习了<Embeded Android>--Karim ...
- 使用 Spring Social 连接社交网络
Spring Social 框架是spring 提供社交平台的分享组件 https://www.ibm.com/developerworks/cn/java/j-lo-spring-social/
- Symbolicating Crash Reports With atos
地址:0x1000e4000 + 49116 = 0x00000001000effdc都是运行时地址: 0x1000e4000:基址偏移后的地址: 0x100000000: 共知基址:各个环境都知道, ...