洛谷 AT_abc036_d [ABC036D] 塗り絵 题解

题目链接

由于是树上问题,又是方案数,可以想到树形 dp。

\(dp_{1,i}\) 表示对结点 \(i\) 为根的子树染色,\(i\) 为黑色的方案数,\(dp_{2,i}\) 则表示 \(i\) 为白色的方案数。

题目中的染色限制是相邻点,所以 dp 转移方程是子推父。白色没有限制,黑色的限制是相邻点不能都是黑。所以父节点是白色时,子节点可以是黑色也可以是白色,父节点是黑色时,子节点只能是白色,再根据加乘原理,可以推出转移方程:

\[dp_{1,u}=\prod dp_{2,v} \]

\[dp_{2,u}=\prod dp_{1,v}+dp_{2,v} \]

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const ll MOD=1000000007;
const int N=1e5+100;
int n,u,v,t[N],k;
ll dp[5][N],ans;
struct node
{
	int id,last;
}a[N*2];
void add(int a1,int a2)
{
	a[++k].id=a2;
	a[k].last=t[a1];
	t[a1]=k;
}
void dfs(int x,int fa)
{
	dp[1][x]=dp[2][x]=1;
	for(int i=t[x];i;i=a[i].last)
	{
		if(a[i].id==fa) continue;
		dfs(a[i].id,x);
		dp[1][x]=(dp[1][x]*dp[2][a[i].id])%MOD;
		dp[2][x]=(dp[2][x]*((dp[1][a[i].id]+dp[2][a[i].id])%MOD))%MOD;
	}
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&u,&v);
		add(u,v),add(v,u);
	}
	dfs(1,0);
	ans=(dp[1][1]+dp[2][1])%MOD;
	printf("%lld",ans);
	return 0;
}
posted @ 2024-08-23 08:30  MinimumSpanningTree  阅读(9)  评论(0)    收藏  举报