专栏文章

CF461B Appleman and Tree 的题解

CF461B题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mimxbtkq
此快照首次捕获于
2025/12/01 17:05
3 个月前
此快照最后确认于
2025/12/01 17:05
3 个月前
查看原文
状态挺神奇的。
考虑设 fu,0/1f_{u,0/1} 在以 uu 为根的子树中,点 uu没有黑点的连通块内有且仅有一个黑点的联通块内的方案数。
那么在合并儿子节点时,设 vvuu 的儿子节点,有方程:
{fu,1fu,1×fv,0+fu,1×fv,1+fu,0×fv,1fu,0fu,0×fv,0+fu,0×fv,1\begin{cases} f_{u,1} &\larr f_{u,1} \times f_{v,0} + f_{u,1} \times f_{v,1} + f_{u,0} \times f_{v,1}\\ f_{u,0} &\larr f_{u,0} \times f_{v,0} + f_{u,0} \times f_{v,1} \end{cases}
初始化为 fu,colu=1f_{u,col_u} = 1
实质上就是枚举了 u,vu,v 之间的边的联通情况对答案的影响。
状态清奇,好思路。
codeCPP
#include<bits/stdc++.h>
#define endl '\n'
//#define MSOD

using namespace std;
using ll = long long;
constexpr ll N = 1e5 + 5, M = 1e9 + 7;

ll n;
ll dp[N][2];
bool col[N];
vector<ll> g[N];
inline void dfs(ll u, ll dad) {
	for(auto v : g[u]) {
		if(v == dad) {
			continue;
		}
		dfs(v, u);
		dp[u][1] = dp[u][1] * dp[v][0] % M + dp[u][1] * dp[v][1] % M + dp[u][0] * dp[v][1] % M;
		dp[u][0] = dp[u][0] * dp[v][0] % M + dp[u][0] * dp[v][1] % M;
		dp[u][1] %= M, dp[u][0] %= M;
	}
	return;
}
inline void solve() {
	cin>>n;
	for(int i = 0 ; i < n - 1 ; i ++) {
		ll x;
		cin>>x;
		g[x].push_back(i + 1), g[i + 1].push_back(x); 
	}
	for(int i = 0 ; i < n ; i ++) {
		cin>>col[i];
		dp[i][col[i]] = 1;
	}
	dfs(0, -1);
	cout<<dp[0][1];
	return;
}

signed main() {
	ios::sync_with_stdio(false), cout.tie(0), cin.tie(0);
	int TC = 1;
#ifdef MSOD
	cin>>TC;
#endif
	while(TC --) {
		solve();
	}
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...