问题 A: Evensgn 剪树枝

时间限制: 1 Sec  内存限制: 128 MB

题目描述

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

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

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

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

的方案?

输入

第一行一个数字 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 号节点是红苹果。

输出

输出一个数字,表示总方案数。答案对 109 + 7 取模。

样例输入

样例输入 2
6
0 1 1 0 4
1 1 0 0 1 0
样例输入 3
10
0 1 2 1 4 4 4 0 8
0 0 0 1 0 1 1 0 0 1

样例输出

样例输出 1
2
样例输出 2
1
样例输出 3
27

提示

数据范围

对于 30% 的数据,1 ≤ n ≤ 10。

对于 60% 的数据,1 ≤ n ≤ 100。

对于 80% 的数据,1 ≤ n ≤ 1000。

对于 100% 的数据,1 ≤ n ≤ 105。

对于所有数据点,都有 0 ≤ pi ≤ n − 1,xi = 0 或 xi = 1。

特别地,60% 中、80% 中、100% 中各有一个点,树的形态是一条链。

   之前这个人刚因为欠债把我坑了一回。。现在又来捡树枝了呜呜呜~~~~(>_<)~~~~

  一眼望去,树归无际。。没错!这道题就是一个很狠狠狠的树归!!

  ::

    我们设f[i][0]为以i为根节点是如果有k个黑苹果,那就正好对其子树剪了k刀,f[i][1]为对其子树剪了k-1刀

因为我们发现如果总共有p个黑苹果,对于整颗树来说一定是剪了p-1根树枝的,那么状态转移一定是有上面俩个状态转移过来的。

所以我们对这个树先进行一遍dfs,预处理出其fa和size数组,size数组的含义是其子树中(包括他自己)含有多少个黑苹果。

那么对于节点i来说,我们要分两种情况进行考虑::

    ①:这个苹果是个黑的,那么所有他的子节点如果为son,f[i][1]一定是有f[son][0]转移过来的,因为包含他自己就代表着他自己没有办法被砍,那这个状态只能是1

    ②:如果这个苹果是红色的,那就要比较麻烦一点了。。首先对于f[i][0]是其所有子节点f[son][0]+f[son][1],带便这这条枝被砍掉,那么f[son][1]就会变为f[son][0],所以要求和。然后对所有的f[son][0]进行相乘(一个简单的分步乘法原理(⊙﹏⊙)b),这就是f[i][0],sum==f[i][0];

    而f[i][1]就为(sum/f[son][0]*f[son][1])的和;因为只有一个是少砍一个的,其他的都是砍满的,方案数相乘。

所以最终的结果就是f[0][1](我是从0开始定义的,而p个苹果必须留一个,所以是1);

除法的时候因为有取模,所以要用逆元处理一下即可。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define mod 1000000007
int n,m,num,x,y;
int adj[],w[];
struct edge{
int s,t,next;
}k[];
int read(){
int sum=;char ch=getchar();
while(ch<''||ch>'') ch=getchar();
while(ch>=''&&ch<=''){sum=sum*+ch-'';ch=getchar();}
return sum;
}
void init(int s,int t){
k[num].s=s;k[num].t=t;
k[num].next=adj[s];adj[s]=num++;
k[num].s=t;k[num].t=s;
k[num].next=adj[t];adj[t]=num++;
}
int f[][];
int fa[],size[];
long long ks(long long p,int n){
long long sq=;
while(n){
if(n&) sq=sq*p%mod;
p=p*p%mod;
n>>=;
}
return sq;
}
void dfs(int x){
if(w[x]) size[x]=;
for(int i=adj[x];i!=-;i=k[i].next){
int o=k[i].t;
if(o!=fa[x]){
fa[o]=x;
dfs(o);
size[x]+=size[o];
}
}
}
void Dp(int x){
long long sum=;
if(!w[x]){
for(int i=adj[x];i!=-;i=k[i].next){
int o=k[i].t;
if(o==fa[x]||!size[o]) continue;
Dp(o);
f[o][]+=f[o][];f[o][]%=mod;
sum*=f[o][];sum%=mod;
}
f[x][]=sum;
for(int i=adj[x];i!=-;i=k[i].next){
int o=k[i].t;
if(o==fa[x]||!size[o]) continue;
int pl=sum*ks(f[o][],mod-)%mod*f[o][]%mod;
f[x][]+=pl;f[x][]%=mod;
}
}
else{
for(int i=adj[x];i!=-;i=k[i].next){
int o=k[i].t;
if(o==fa[x]||!size[o]) continue;
Dp(o); f[o][]+=f[o][];f[o][]%=mod;
sum*=f[o][];sum%=mod;
}
f[x][]=sum;
}
}
int main(){
//freopen("tree.in","r",stdin);
//freopen("tree.out","w",stdout);
memset(fa,-,sizeof(fa));
memset(adj,-,sizeof(adj));
n=read();
for(int i=;i<n;++i){
x=read();
init(x,i);
}
for(int i=;i<n;++i)
w[i]=read();
dfs();Dp();
printf("%d\n",f[][]);
return ;
}

Evensgn 捡树枝的更多相关文章

  1. [繁华模拟赛]Evensgn 剪树枝

    Evensgn 剪树枝 题目 繁华中学有一棵苹果树.苹果树有 n 个节点(也就是苹果),n − 1 条边(也就 是树枝).调皮的 Evensgn 爬到苹果树上.他发现这棵苹果树上的苹果有两种:一 种是 ...

  2. 繁华模拟赛 Evensgn剪树枝

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

  3. Evensgn 剪树枝 树规

    f[x][0]表示与其父边相连的连通块内没有黑苹果的方案数, f[x][1]则表示有黑苹果, 如果父边被切断,相当于没有黑苹果 初始化时,假设切掉父边,f[x][0]=1,f[x][1]=0; 递归回 ...

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

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

  5. kindle书摘-活着-余华-活着不易,珍惜

     https://github.com/starrtc/android-demo 中文版自序 标注(黄色) - 位置 29 作家的使命不是发泄,不是控诉或者揭露,他应该向人们展示高尚.这里所说的高尚不 ...

  6. 暑假集训D16总结

    考试 日常爆炸= = T1 一看就是个树规,然而不会写方程= = T2 一看就是个分块,然而不会分= = T3 终于有点头绪,推了两个小时的30分部分分情况,然后打挂了= = 我玩个鬼啊 其实听完,觉 ...

  7. 清北学堂模拟day4 捡金币

    [问题描述]小空正在玩一个叫做捡金币的游戏.游戏在一个被划分成 n行 n列的网格状场地中进行.每一个格子中都放着若干金币,并且金币的数量会随着时间而不断变化. 小空的任务就是在网格中移动,拾取尽量多的 ...

  8. 捡火柴的Nova君(n个线段相交问题)

    题目来源:https://biancheng.love/contest-ng/index.html#/41/problems 捡火柴的Nova君 题目描述 南方没暖气,怕冷的的宝宝们只能用火柴取暖.然 ...

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

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

随机推荐

  1. SIMD---AVX系列

    AVX全称Advanced Vcetor Extension,是对SSE的后续扩展,主要分为AVX.AVX2.AVX512三种.在目前常见的机器上,大多只支持到AVX系列,因此其他SIMD扩展指令我们 ...

  2. Kettle 初始配置数据量类型资源库

    PS:有段时间不使用Kettle了,但总遇到小伙伴问起,写一篇记录下. 文档使用版本:KETTLE 7.0 Kettle资源库可分为文件与数据库,文件型只需要配置好存放路径就行,这边介绍的是配置数据库 ...

  3. Leetcode 4——Partition List

    Problems: Given a linked list and a value x, partition it such that all nodes less than x come befor ...

  4. 项目Alpha冲刺Day10

    一.会议照片 二.项目进展 1.今日安排 解决前后台联调问题,完善全局的请求和路由跳转处理,添加空文件完善路由信息,优化界面跳转等待.完成个人信息和修改密码.修改前台数据组织和方法调用方式.解决登录和 ...

  5. thinkphp调试技巧

    调试的经验:很多时候程序调试不出来,但是又找不出错误,往往是拼写错误可能是很小的拼写错误,很难看出,或者多了一个空格,比如在配置路由的时候'URL_ROUTER_ON '=true,这样设置就会错误, ...

  6. 前端基础之html-Day12

    1.web服务本质 import socket def main(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bi ...

  7. 阿里云API网关(14)流控策略

    网关指南: https://help.aliyun.com/document_detail/29487.html?spm=5176.doc48835.6.550.23Oqbl 网关控制台: https ...

  8. Docker学习笔记 - Docker客户端和服务端

    学习内容: Docker客户端和服务端的通讯方式:client和自定义程序 Docker客户端和服务端的连接方式:socket 演示Docker客户端和服务端之间用remote-api通讯:nc   ...

  9. QT5.5与MYSQL5.6数据库连接的具体方法与实现

    由于毕设需要用到QT读取数据库中的数据,并将数据保存至数据库中.花了一天的时间,总算实现了从QT中读取数据库中的数据.网上相关资料很多,但是写得不是很全,中间出现了一些问题,解决起来比较麻烦.所以本文 ...

  10. Java面向对象之构造函数 入门实例

    一.基础概念 1.什么时候定义构造函数: 当对象创建时,需要对象必须具备的内容,通过构造函数完成. 2.一般函数和构造函数的区别: 定义上:构造函数只为对象的初始化,只执行一次.一般函数定义对象应该具 ...