NC13611-树-(dp)

链接:https://ac.nowcoder.com/acm/problem/13611
来源:牛客网

题目描述

shy有一颗树,树有n个结点。有k种不同颜色的染料给树染色。一个染色方案是合法的,当且仅当对于所有相同颜色的点对(x,y),x到y的路径上的所有点的颜色都要与x和y相同。请统计方案数。

输入描述:

第一行两个整数n,k代表点数和颜色数;
接下来n-1行,每行两个整数x,y表示x与y之间存在一条边;

输出描述:

输出一个整数表示方案数(mod 1e9+7)。
示例1

输入

复制 
4 3
1 2
2 3
2 4

输出

复制 
39

备注:

对于30%的数据,n≤10, k≤3;
对于100%的数据,n,k≤300。

 

一直以为树的题目要用dfs解决,难得见到不用的。

n个点的树,看作一张连通图,任意两点路径上的点要相同颜色,也就是两点间的一片都要相同颜色,看作是一个连通分量,颜色有k种,任选多少种涂都行,在颜色上不做要求。

对于一个连通图,加上一个点,这个点的涂色方法,可以选择旧颜色和新颜色。

dp[i][j]表示i个点的联通图用j种颜色涂色的方案数量

对于第i个点,涂旧颜色即dp[i-1][j],涂新颜色即dp[i-1][j-1]*(k-(j-1));

dp[i][j]=dp[i-1][j]+dp[i-1][j-1]*(k-(j-1));

最后将n个点的连通图加起来就好。

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<math.h>
#include<string>
#include<map>
#include<queue>
#include<stack>
#include<set>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int p=1e9+7;
ll dp[305][305];

int main()///NC13611
{
    int n,k;
    scanf("%d%d",&n,&k);
    memset(dp,0,sizeof(dp));
    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]*(k-(j-1));
            dp[i][j]%=p;
        }
    }
    ll ans=0;
    for(int i=1;i<=k;i++)
        ans=(ans+dp[n][i])%p;
    printf("%lld\n",ans);

    return 0;
}

数论解法:

 

 

 

posted @ 2020-04-09 15:37  守林鸟  阅读(212)  评论(0编辑  收藏  举报