Luogu3914 染色计数

Description

link

给定一棵 (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();}
原文地址:https://www.cnblogs.com/yspm/p/13234381.html