Description
给定一棵 (n) 个点的树,树上的每个点可以涂 (m) 种颜色的中的几种
规定相邻的两个点涂的颜色不一样,求方案数
(n,m le 5000)
Solution
定义状态:
(f_{x,y}) 为点 (x) 涂颜色 (y) 的时候的子树里的方案数
那么答案就是
[sum_{i=1&&iin {col_1}}^m f_{1,i}
]
转移就是把每个儿子上面颜色不一样的求和乘起来
我们发现这个做法是 (O(n^3)) 的,并不能通过
然后我们优化一下这个转移,把每个儿子的方案求个和
对应乘的时候直接减掉那个颜色就成了
Code
#include<bits/stdc++.h>
using namespace std;
namespace yspm{
inline int read()
{
int res=0,f=1; char k;
while(!isdigit(k=getchar())) if(k=='-') f=-1;
while(isdigit(k)) res=res*10+k-'0',k=getchar();
return res*f;
}
const int mod=1e9+7,N=5010;
int n,m,head[N],cnt;
struct node{
int to,nxt;
}e[N<<1];
inline void add(int u,int v)
{
e[++cnt].to=v; e[cnt].nxt=head[u];
return head[u]=cnt,void();
}
int sum[N],f[N][N];
inline void dfs(int x,int fa)
{
for(int i=head[x];i;i=e[i].nxt)
{
int t=e[i].to;
if(t==fa) continue; dfs(t,x);
for(int j=1;j<=m;++j)
{
f[x][j]=1ll*f[x][j]*((sum[t]-f[t][j]+mod)%mod)%mod;
}
}
for(int i=1;i<=m;++i) sum[x]=(sum[x]+f[x][i])%mod;
return ;
}
signed main()
{
n=read(); m=read();
for(int tmp,i=1;i<=n;++i)
{
tmp=read(); while(tmp--) f[i][read()]=1;
}
for(int i=1,u,v;i<n;++i) u=read(),v=read(),add(u,v),add(v,u);
dfs(1,0); printf("%d
",sum[1]);
return 0;
}
}
signed main(){return yspm::main();}