1. 程式人生 > 實用技巧 >[洛谷] P3914 染色計數

[洛谷] P3914 染色計數

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;
}