[洛谷3914]染色计数

题目大意:有一颗 $N$ 个节点的树,节点用 $1,2,\cdots,N$ 编号。你要给它染色,使得相邻节点的颜色不同。有 $M$ 种颜色,用 $1,2,\cdots,M$ 编号。每个节点可以染 $M$ 种颜色中的若干种,求不同染色方案的数量

题解:树形$DP$,$f_{i,j}$表示第$i$个点,涂色为$j$的方案数,$f_{i,0}$表示改点所有的涂色方案

$$f_{i,j}=\prod\limits_{k为i的儿子}(f_{k,0}-f_{k,j})(第i个点可以涂成j颜色)$$

卡点:1.为了防止爆$int$,我采用了$0ll$加一个数,然而优先级过低,那个数先炸了。。。

 

C++ Code:

 

#include <cstdio>
#define maxn 5010
using namespace std;
const int mod = 1000000007;
int n, m, a, b;
int f[maxn][maxn];
int head[maxn], cnt;
struct Edge {
	int to, nxt;
} e[maxn << 1];
void add(int a, int b) {
	e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;
}
int fa[maxn];
void dfs(int rt) {
	int v;
	for (int i = head[rt]; i; i = e[i].nxt) {
		v = e[i].to;
		if (v != fa[rt]) {
			fa[v] = rt;
			dfs(v);
			for (int j = 1; j <= m; j++) {
				f[rt][j] = (1ll * f[rt][j] * (f[v][0] - f[v][j])) % mod;
			}
		}
	}
	for (int i = 1; i <= m; i++) if (f[rt][i] < 0) f[rt][i] += mod;
	for (int i = 1; i <= m; i++) f[rt][0] = (f[rt][0] + f[rt][i]) % mod;
}
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a);
		for (int j = 1; j <= a; j++) scanf("%d", &b), f[i][b] = 1;
	}
	for (int i = 1; i < n; i++) {
		scanf("%d%d", &a, &b);
		add(a, b);
		add(b, a);
	}
	dfs(1);
	printf("%d\n", f[1][0]);
	return 0;
}

 

 

 

  

posted @ 2018-08-20 15:02  Memory_of_winter  阅读(162)  评论(0编辑  收藏  举报