题目链接:https://ac.nowcoder.com/acm/problem/13611
题意:shy有一颗树,树有n个结点。有k种不同颜色的染料给树染色。一个染色方案是合法的,当且仅当对于所有相同颜色的点对(x,y),x到y的路径上的所有点的颜色都要与x和y相同。请统计方案数。
思路:
1、
d
p
dp
dp
我们用
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示用
j
j
j种颜色去染
i
i
i个结点的方案数,那我就有两种情况:
(1)、
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
]
;
dp[i][j] = dp[i-1][j];
dp[i][j]=dp[i−1][j];
(2)、
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
−
1
]
×
(
k
−
(
j
−
1
)
)
;
dp[i][j] = dp[i-1][j-1]\times(k - (j-1));
dp[i][j]=dp[i−1][j−1]×(k−(j−1));
所以
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
]
+
d
p
[
i
−
1
]
[
j
−
1
]
×
(
k
−
(
j
−
1
)
)
;
dp[i][j] = dp[i-1][j] + dp[i-1][j-1]\times(k - (j-1));
dp[i][j]=dp[i−1][j]+dp[i−1][j−1]×(k−(j−1));
最后答案就是
∑
i
=
1
k
d
p
[
n
]
[
i
]
\sum_{i=1}^{k}dp[n][i]
∑i=1kdp[n][i]
就搞不懂这个题给我们一颗树干嘛
AC代码如下:
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL long long
#define pii pair<int,int>
#define sd(x) scanf("%d",&x)
#define slld(x) scanf("%lld",&x)
#define pd(x) printf("%d\n",x)
#define plld(x) printf("%lld\n",&x)
#define rep(i,a,b) for(int i = a ; i <= b ; i++)
#define per(i,a,b) for(int i = b ; i >= a ; i--)
#define mem(a) memset(a,0,sizeof(a))
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define fast_io ios::sync_with_stdio(false)
const int INF = 1e9;
const LL mod = 1e9 + 7;
const int maxn = 3e2 + 7;
LL dp[maxn][maxn];
int main() {
int n,k;
while(~scanf("%d%d",&n,&k)) {
for(int i = 1 ; i < n ; i++) {
int u,v;
scanf("%d%d",&u,&v);
}
memset(dp,0,sizeof(dp));
dp[0][0] = 1;
for(int i = 1 ; i <= n ; i++) {
for(int j = 1 ; j <= min(i,k) ; j++) {
dp[i][j] = (dp[i-1][j] + dp[i-1][j-1] * (1LL * (k - j + 1))) % mod;;
}
}
LL ans = 0;
for(int i = 1 ; i <= k ; i++) {
ans = (ans + dp[n][i]) % mod;
}
printf("%lld\n",ans);
}
return 0;
}
2、数论
首先我们分析一下这个题目,其实就是让我们将这棵树分成最多
m
i
n
(
n
,
k
)
min(n,k)
min(n,k)个连通块,每个连通块里的结点颜色相同,求方案数。
既然如此,我们要将这棵树分成若干个连通块,那我们就要删边,而且,如果我们要将这棵树分成
i
i
i个连通块,那我们就需要删掉
i
−
1
i-1
i−1条边,那方案数就是
C
(
n
−
1
,
i
−
1
)
C(n-1,i-1)
C(n−1,i−1),那我们现在就需要对已经分好的
i
i
i个连通块进行染色,一共
k
k
k种颜色,取
i
i
i个,而且还要考虑顺序,所以方案数就是
A
(
k
,
i
)
A(k,i)
A(k,i),那么答案就是
∑
i
−
1
m
i
n
(
n
,
k
)
C
(
n
−
1
,
i
−
1
)
×
A
(
k
,
i
)
\sum_{i-1}^{min(n,k)}C(n-1,i-1)\times A(k,i)
∑i−1min(n,k)C(n−1,i−1)×A(k,i)。
AC代码如下:
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL long long
#define pii pair<int,int>
#define sd(x) scanf("%d",&x)
#define slld(x) scanf("%lld",&x)
#define pd(x) printf("%d\n",x)
#define plld(x) printf("%lld\n",x)
#define rep(i,a,b) for(int i = (a) ; i <= (b) ; i++)
#define per(i,a,b) for(int i = (b) ; i >= (a) ; i--)
#define mem(a) memset(a,0,sizeof(a))
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define fast_io ios::sync_with_stdio(false)
const int INF = 1e9;
const LL mod = 1e9 + 7;
const int maxn = 3e2 + 7;
LL f[maxn],inv[maxn];
LL C(LL x,LL y) {
return f[x] * inv[y] % mod * inv[x-y] % mod;
}
LL A(LL x,LL y) {
return f[x] * inv[x-y] % mod;
}
int main() {
inv[0] = f[0] = inv[1] = f[1] = 1;
for(LL i = 2 ; i <= maxn ; i++) {
inv[i] = ((mod - mod / i) * inv[mod%i]) % mod;
f[i] = i;
}
for(LL i = 2 ; i <= maxn ; i++) {
inv[i] = (inv[i] * inv[i-1]) % mod;
f[i] = (f[i] * f[i-1]) % mod;
}
LL n,k;
while(~scanf("%lld%lld",&n,&k)) {
rep(i,1,n-1) {
LL x,y;
scanf("%lld%lld",&x,&y);
}
LL ans = 0;
for(LL i = 1 ; i <= n && i <= k ; i++) {
ans = (ans + (C(n-1,i-1) * A(k,i) % mod)) % mod;
}
plld(ans);
}
}