1. 程式人生 > >洛谷 P3914 染色計數

洛谷 P3914 染色計數

mat hold name amp using radi 表示 思路 right

P3914 染色計數

題目描述

有一顆NN個節點的樹,節點用1,2,\cdots,N1,2,?,N編號。你要給它染色,使得相鄰節點的顏色不同。有MM種顏色,用1,2,\cdots,M1,2,?,M編號。每個節點可以染MM種顏色中的若幹種,求不同染色方案的數量除以(10^9 + 7109+7)的余數。

輸入輸出格式

輸入格式:

第1 行,2 個整數N,MN,M。

接下來NN行,第ii行表示節點ii可以染的顏色。第1個整數k_iki?,表示可以染的顏色數量。接下來k_iki?個整數,表示可以染的顏色編號。

最後N - 1N1行,每行2個整數A_i,B_iAi?,Bi?,表示邊(A_i,B_i)(Ai?,Bi?)。

輸出格式:

1 個整數,表示所有的數。

輸入輸出樣例

輸入樣例#1: 復制
2 2
1 1
2 1 2
1 2
輸出樣例#1: 復制
1

說明

• 對於30% 的數據,1 \le N \le 10; 1 \le M \le 41N10;1M4;

• 對於60% 的數據,1 \le N \le 200; 1 \le M \le 2001N200;1M200;

• 對於100% 的數據,1 \le N \le 5000; 1 \le M \le 50001N5000;1M5000。

思路:組合數學+樹形DP。

f[i][j]表示在以i為根的子樹中,當i號節點的顏色為j時的方案數。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define mod 1000000007
#define MAXN 5010
using namespace std;
int n,m,tot;
int ans[MAXN],f[5010][5010];
int to[MAXN*2],net[MAXN*2],head[MAXN*2];
void add(int
u,int v){ to[++tot]=v;net[tot]=head[u];head[u]=tot; to[++tot]=u;net[tot]=head[v];head[v]=tot; } void dfs(int now,int fa){ for(int i=head[now];i;i=net[i]) if(to[i]!=fa) dfs(to[i],now); for(int i=1;i<=m;i++) if(f[now][i]){ for(int j=head[now];j;j=net[j]) if(to[j]!=fa) f[now][i]=1LL*f[now][i]*(ans[to[j]]-f[to[j]][i])%mod; while(f[now][i]<0) f[now][i]+=mod; ans[now]=(ans[now]+f[now][i])%mod; } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ int k;scanf("%d",&k); for(int j=1;j<=k;j++){ int q;scanf("%d",&q); f[i][q]++; } } for(int i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); add(x,y); } add(0,1); dfs(0,0); printf("%d",ans[1]); }

洛谷 P3914 染色計數