dfs序+線性dp 樹

題目描述

shy有一顆樹,樹有n個結點。有k種不同顏色的染料給樹染色。一個染色方案是合法的,當且僅當對於所有相同顏色的點對(x,y),x到y的路徑上的所有點的顏色都要與x和y相同。請統計方案數。

輸入描述:

第一行兩個整數n,k代表點數和顏色數;
接下來n-1行,每行兩個整數x,y表示x與y之間存在一條邊;

輸出描述:

輸出一個整數表示方案數(mod 1e9+7)。


看上去是樹形dp;

這題要是沒想到把樹上問題轉化爲dfs序是很難做的出來的;

轉化爲dfs序,就是一道線性dp,dp[i][j]表示前 i 個結點用 j 種顏色塗有多少種塗法;

那麼轉移方程爲:dp[i][j]=dp[i-1][j]+dp[i-1][j-1]*(k-j+1);

分別表示在第 i 個點取一個已經出現過的顏色,在第 i 點取個新顏色(前面 i-1 個點沒出現過);

爲啥取一個已經出現過的顏色是 dp[i-1][j] ,因爲如果第 i 個點塗的色在前 i-1 個結點中就已經出現過,第 i 個點必須和它父親結點顏色相同;

看到這裏,發現dfs序已經不重要了,什麼樹都是這樣的;

代碼:

#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=1100;
const int M=50100;
const LL mod=1e9+7;
int n,k;
LL dp[N][N];
int main(){
	cin>>n>>k;
	for(int i=1;i<n;i++){
		int x,y;cin>>x>>y;
	}
	dp[0][0]=1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=k;j++){
			dp[i][j]=dp[i-1][j]+dp[i-1][j-1]*(1ll*(k-j+1)); 
			dp[i][j]%=mod;
		}
	}
	LL ans=0;
	for(int i=1;i<=k;i++) (ans+=dp[n][i])%=mod;
	cout<<ans<<endl;
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章