CF461B Appleman and Tree题解
创始人
2024-02-05 20:14:12
0次

洛谷题面
在这里插入图片描述
感觉是非常经典的一道题,最近好像总是见到,今天也算给它做了,发一篇题解来记录一下。

这道题是一道树形 DP 题,设 f[u][0/1]f[u][0/1]f[u][0/1] 表示 uuu 点属于一个无黑点 /// 有且仅有一个黑点的联通块时的方案数。我们考虑如何进行转移。

对于 f[u][1]f[u][1]f[u][1],我们考虑如果 uuu 在一个有且仅有一个黑点的联通块时,对于它的儿子 vvv,有三种情况:

  1. 儿子是不合法的,那么我们需要把儿子和 uuu 放在一个联通块里,也就是儿子要贴着父亲,对应的贡献是f[u][1]×f[v][0]f[u][1] \times f[v][0]f[u][1]×f[v][0]。
  2. 儿子是合法的,那么我们可以从中间断开,对应的贡献是 f[u][1]×f[v][1]f[u][1] \times f[v][1]f[u][1]×f[v][1]。
  3. 父亲是不合法的,那么需要把 uuu 和它的儿子放到一个联通块里,对应的贡献是 f[u][0]×f[v][1]f[u][0] \times f[v][1]f[u][0]×f[v][1]。

所以对于 f[u][1]f[u][1]f[u][1] 的转移就是 f[u][1]=f[u][1]×(f[v][0]+f[v][1])+f[u][0]×f[v][1]f[u][1] = f[u][1] \times (f[v][0] + f[v][1]) + f[u][0] \times f[v][1]f[u][1]=f[u][1]×(f[v][0]+f[v][1])+f[u][0]×f[v][1]。

对于 f[u][0]f[u][0]f[u][0],有两种情况:

  1. 父亲不合法的同时,儿子也不合法,那么把父亲和儿子放在一起,对应的贡献是 f[u][0]×f[v][0]f[u][0] \times f[v][0]f[u][0]×f[v][0]。
  2. 父亲不合法,但儿子合法,那么就从中间断开,对应的贡献是 f[u][0]×f[v][1]f[u][0] \times f[v][1]f[u][0]×f[v][1]。

所以对于 f[u][0]f[u][0]f[u][0] 的转移就是 f[u][0]=f[u][0]×(f[v][0]+f[v][1])f[u][0] = f[u][0] \times (f[v][0] + f[v][1])f[u][0]=f[u][0]×(f[v][0]+f[v][1])。

初始的状态是 f[u][color[u]]=1f[u][color[u]] = 1f[u][color[u]]=1,最后的答案如果以 111 为根的话就是 f[1][1]f[1][1]f[1][1]。

#include 
#define ll long long
#define drep(a,b,c) for(int a(b) ; a>=(c) ; --a)
#define rep(a,b,c) 	for(int a(b) ; a<=(c) ; ++a)
using namespace std;
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch == '-') f=-1 ; ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
}
inline void print(int x){if(x < 0) putchar('-'),x = -x;if(x >= 10) print(x / 10);putchar(x % 10 + '0');
}
const int M = 2e5+10;
const int mod = 1e9+7;
int n,cnt;
int head[M],col[M];
ll f[M][2];
struct Edge{int to,nxt;
}e[M<<1];
inline void add(int u,int v){e[++cnt].to = v;e[cnt].nxt = head[u];head[u] = cnt;
}
void dfs(int u,int fa){f[u][col[u]] = 1;for(int i(head[u]) ; i ; i=e[i].nxt){int v = e[i].to;if(v == fa) continue;dfs(v,u);f[u][1] = f[u][1] * f[v][1] % mod + f[u][1] * f[v][0] % mod + f[u][0] * f[v][1] % mod;f[u][0] = f[u][0] * f[v][0] % mod + f[u][0] * f[v][1] % mod;f[u][1] %= mod;f[u][0] %= mod;}
}
signed main(){n = read();rep(i,2,n){int u = read() + 1;add(u,i),add(i,u);}rep(i,1,n) col[i] = read();dfs(1,0);printf("%lld\n",f[1][1]);return 0;
}

相关内容

热门资讯

前端-session、jwt 目录:   (1)session (2&#x...
linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
关于测试,我发现了哪些新大陆 关于测试 平常也只是听说过一些关于测试的术语,但并没有使用过测试工具。偶然看到编程老师...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
nodejs:本地安装nvm实... 一、背景-使用不同版本node的原因 vue3+ts、nuxt3版本,node...
JAVA集合知识整理 Java集合知识整理 HashMap相关 HashMap的底层数据结构:jdk1.8之...
无刷直流电机介绍及单片机控制实... 无刷直流电机介绍及单片机控制实例前言基本概念优势与劣势使用寿命基本结构使用单片机控制实例电子调速器&...
fwdiary(2) dp2 1.传纸条  AcWing 275. 传纸条 - AcWing 走两条路,走一条最大的...
常用的DOS命令 常用的DOS命令 DOS(Disk Operating System,磁...
<C++> 类和对象(下) 1.const成员函数将const修饰的“成员函数”称之为const成员函数,cons...