正题
题目链接:https://www.luogu.org/problemnew/show/P3914
题目大意
nnn个点每个点有些可以染的颜色,要求相邻颜色不相同,方案总数。
解题思路
树形dpdpdp,定义fx,if_{x,i}fx,i表示点xxx的染颜色iii的方案数。然后定义zx=∑i=1mfxiz_x=\sum_{i=1}^mf_{x_i}zx=∑i=1mfxi
然后显然动态转移方程fx,i=zy−fy,i(x−>y)f_{x,i}=z_y-f_{y,i}(x->y)fx,i=zy−fy,i(x−>y)
codecodecode
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int XJQ=1e9+7,N=5001;
int tot,n,m,f[N][N],z[N],ls[N];
struct node{int to,next;
}a[2*N];
void addl(int x,int y)
{a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;
}
void dp(int x,int fa)
{for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa) continue;dp(y,x);int k=1;for(int j=1;j<=m;j++)f[x][j]=1ll*f[x][j]*((z[y]-f[y][j]+XJQ)%XJQ)%XJQ;}for(int j=1;j<=m;j++)(z[x]+=f[x][j])%=XJQ;
}
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){int k,x;scanf("%d",&k);for(int j=1;j<=k;j++)scanf("%d",&x),f[i][x]=1;}for(int i=1;i<n;i++){int x,y;scanf("%d%d",&x,&y);addl(x,y);addl(y,x);}dp(1,0);printf("%d",z[1]);
}