Barn Painting

Barn PaintingBarn\ Painting

題目鏈接:jzoj 6657jzoj\ 6657 / luogu 4084luogu\ 4084

題目

給定一顆NN個節點組成的樹,33種顏色,其中KK個節點已染色,要求任意兩相鄰節點顏色不同,求合法染色方案數。

輸入

11行:NNKK
2N2~N行:xxyy代表點xx和點yy
N+1N+KN+1~N+K行:bbcc代表點bb已經被塗上了顏色cc

輸出

合法的染色方案數 %109+7\%10^9+7

樣例輸入

4 1
1 2
1 3
1 4
4 3

樣例輸出

8

數據範圍

1N1051≤N≤10^50KN0≤K≤N
1x,yN1≤x,y≤Nxyx≠y
1bN1≤b≤N1c31≤c≤3

思路

這道題是一道樹形dpdp
我們設f[i][j]f[i][j]爲在點ii塗顏色jj的方案數,那麼首先初始化,我們把所有點塗所有顏色的方案數都是11
接着,我們來處理數據中直接塗了顏色的點。這個也很好做,就是把這個點塗了的顏色的方案數標爲11,剩下的兩個顏色方案數標爲00
接着我們就要開始dpdp,就按照與一個點相鄰的點不能跟它是同一個顏色的原則,我們就可以寫出dpdp式。

注意:

  1. 要開long longlong\ long
  2. 要記得取模

代碼

#include<cstdio>
#include<cstring>
#define mo 1000000007
#define ll long long

using namespace std;

struct node{
	int to, next;
}e[200001];
int n, k, x, y, kk, le[200001];
ll f[200001][4];

void add(int x, int y) {//連邊
	e[++kk] = (node){y, le[x]}; le[x] = kk;
}

void dfs(int now, int fa) {//樹形dp
	for (int i = le[now]; i; i = e[i].next)
		if (e[i].to != fa) {
			dfs(e[i].to, now);
			f[now][1] = f[now][1] * ((f[e[i].to][2] + f[e[i].to][3]) % mo) % mo;//三個dp式,分別表示塗這三個顏色的方案數
			f[now][2] = f[now][2] * ((f[e[i].to][1] + f[e[i].to][3]) % mo) % mo;
			f[now][3] = f[now][3] * ((f[e[i].to][1] + f[e[i].to][2]) % mo) % mo;
		}
}

int read() {//快讀
	int re = 0, zf = 1;
	char c = getchar();
	while (c < '0' || c > '9') {
		if (c = '-') zf = -zf;
		c = getchar();
	}
	while (c >= '0' && c <= '9') {
		re = re * 10 + c - 48;
		c = getchar();
	}
	return re * zf;
}

int main() {
//	freopen("barnpainting.in", "r", stdin);
//	freopen("barnpainting.out", "w", stdout);
	
	n = read();//讀入
	k = read();//讀入
	
	for (int i = 1; i <= n; i++)
		f[i][1] = f[i][2] = f[i][3] = 1;//初始化
	
	for (int i = 1; i < n; i++) {
		x = read();//讀入
		y = read();//讀入
		add(x, y);//連邊
		add(y, x);//兩個方向又要連邊
	}
	for (int i = 1; i <= k; i++) {
		x = read();//讀入
		y = read();//讀入
		for (int i = 1; i <= 3; i++)
			f[x][i] = 0;//如果一個點已經塗色,那麼這個點就不可能塗其他顏色
		f[x][y] = 1;//就只能塗這個顏色
	}
	
	dfs(1, 0);//樹形dp
	
	printf("%lld", (f[1][1] + f[1][2] + f[1][3]) % mo);//輸出答案
	
//	fclose(stdin);
//	fclose(stdout);
	
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章