洛谷 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;
}

浙公网安备 33010602011771号