第十三章lca B-树 dfn序 线性DP
链接:https://ac.nowcoder.com/acm/contest/27836/B
来源:牛客网
题目描述
shy有一颗树,树有n个结点。有k种不同颜色的染料给树染色。一个染色方案是合法的,当且仅当对于所有相同颜色的点对(x,y),x到y的路径上的所有点的颜色都要与x和y相同。请统计方案数。
输入描述:
第一行两个整数n,k代表点数和颜色数; 接下来n-1行,每行两个整数x,y表示x与y之间存在一条边;
输出描述:
输出一个整数表示方案数(mod 1e9+7)。
备注:
对于30%的数据,n≤10, k≤3; 对于100%的数据,n,k≤300。
分析
按照题目所说,所有颜色相等的两个节点之间的所有节点颜色相等
很容易想到dfn序里一个区间内颜色相等。
思考这颗树,可以想到如果一个新的节点颜色和之前的节点相等的话,那这个节点也必然和这个节点的根节点颜色相等
所以每个新的节点它的颜色要么和它的根节点颜色相等,要么和之前所有节点的颜色都不相等。
这样考虑最后一个点的问题,很容易想到线性DP。
设dp[i][j] 表示前i 个点,已经有了j 种颜色
dp[i][j] = d[i-1][j] + dp[i-1][j-1] * (k - 1 + 1) ;; 第i个节点要么和前面所有节点颜色相等(不出现新的颜色),要么与前面所有节点的颜色不相等(前面有j - 1 种颜色,当前节点有(k - j + 1)种可能)
建成一颗树只是迷惑,关键还是要把顺序理清楚,搞清楚关键点是根节点。
//-------------------------代码---------------------------- //#define int ll const int N = 2e6+10,mod = 1e9+7; int n,m,k; ll f[500][500]; void solve() { // cin>>n>>m; cin>>n>>k; fo(i,1,n-1)cin>>m>>m; f[0][0] = 1; fo(i,1,n) { of(j,k,1) { // fo(j,1,k) { f[i][j] = (f[i-1][j] + f[i-1][j-1] * (k - j + 1)) % mod; } } ll sum = 0; fo(i,1,k) { sum = (sum + f[n][i]) % mod; // fo(j,1,k) { // cout<<f[i][j]<<' '; // } cout<<endl; } // cout<<f[n][k]<<endl; cout<<sum % mod<<endl; } signed main(){ AC(); clapping();TLE; // while(cin>>n,n) // while(cin>>n>>m,n,m) // int t;cin>>t;while(t -- ) solve(); // {solve(); } return 0; } /*样例区 */ //------------------------------------------------------------