[洛谷] P3914 染色計數
阿新 • • 發佈:2020-12-03
Description
有一顆\(N\)個節點的樹,節點用\(1,2,\cdots,N\)編號。你要給它染色,使得相鄰節點的顏色不同。有\(M\)種顏色,用\(1,2,\cdots,M\)編號。每個節點可以染\(M\)種顏色中的若干種,求不同染色方案的數量除以\(10^9 + 7\)的餘數。
Solution
設狀態\(dp[i][j]\)為節點\(i\),顏色為\(j\)的方案數,則有
\[dp[i][j]=\sum_{k=1,k!=j}^ndp[son[i]][k](初始化dp[i][col[i]]=1) \]然後這個可以\(dfs\)的時候順便處理\(dp[i][1\sim{m}]\)的和,就可以做到\(O(nm)\)
類似的題有P4084 [USACO17DEC]Barn Painting G
Code
#include <bits/stdc++.h> using namespace std; const int mod = 1e9 + 7; int n, m, tot, res, vis[5005], hd[5005], to[10005], nxt[10005], sum[5005], dp[5005][5005]; int read() { int x = 0, fl = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();} while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + ch - '0'; ch = getchar();} return x * fl; } void add(int x, int y) { tot ++ ; to[tot] = y; nxt[tot] = hd[x]; hd[x] = tot; return; } void dfs(int x, int fa) { for (int i = hd[x]; i; i = nxt[i]) { int y = to[i]; if (y == fa) continue; dfs(y, x); for (int p = 1; p <= m; p ++ ) dp[x][p] = (1ll * dp[x][p] * (sum[y] - dp[y][p]) % mod + mod) % mod; } for (int p = 1; p <= m; p ++ ) sum[x] = (sum[x] + dp[x][p]) % mod; return; } int main() { n = read(); m = read(); for (int i = 1; i <= n; i ++ ) { int t = read(); while (t -- ) { int col = read(); dp[i][col] = 1; } } for (int i = 1; i <= n - 1; i ++ ) { int x = read(), y = read(); add(x, y); add(y, x); } dfs(1, 0); for (int p = 1; p <= m; p ++ ) res = (res + dp[1][p]) % mod; printf("%d\n", res); return 0; }