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