dp做法
时间复杂度。
在树中选择任意一个叶子结点作为起点,沿着边一个点接一个点的涂色。定义为前
个点使用了
种颜色的方案数,状态转移方程:
- 若第
个点选用未使用的颜色,则
。
- 若第
个点选用已经使用过的颜色,则必须和
的颜色相同,若和更前面的结点颜色相同则在路径中会经过
不符合题意,则
。
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int INF = 0x3f3f3f3f; ///1 061 109 567
const int negative_infinite = 0xcfcfcfcf; ///-808 464 433
const double pi = acos(-1);
const int mod = 1e9 + 7;
const double eps = 1e-8;
const int MAXN = 5e5 + 117;
const int MAXM = 2e5 + 117;
int n, k;
int u, v;
LL dp[377][377];
int main() {
scanf("%d%d", &n, &k);
for(int i = 1; i < n; i++) scanf("%d%d", &u, &v);
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] %= mod;
}
}
for(int j = 1; j <= k; j++) {
dp[n][j] = (dp[n][j] + dp[n][j - 1]) % mod;
}
printf("%lld\n", dp[n][k]);
return 0;
} 连通块做法
时间复杂度,下面代码中的逆元可以进一步优化。
问题转化为把一棵树分成多个连通块,每个连通块内的结点涂相同的颜色,不同的连通块颜色不同,有多少种方案。
- 若把
个结点的树分成
个连通块,则需要删除
条边,有
种方案。
种颜色需要选出
种,有
种方案。
种颜色涂
个连通块,有
种方案。
- 上面三个条件满足乘法原理,则对答案的贡献为
,最后只需要枚举一下可以分成多少个连通块求和即可。
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int INF = 0x3f3f3f3f; ///1 061 109 567
const int negative_infinite = 0xcfcfcfcf; ///-808 464 433
const double pi = acos(-1);
const int mod = 1e9 + 7;
const double eps = 1e-8;
const int MAXN = 5e5 + 117;
const int MAXM = 2e5 + 117;
int n, k;
int u, v;
LL fac[377], sum;
LL fast_pow(LL a, LL n) {
LL ret = 1, temp = a % mod;
while(n) {
if(n & 1) ret = ret * temp % mod;
temp = temp * temp % mod;
n >>= 1;
}
return ret;
}
LL Comb(int n, int m) {
return fac[n] * fast_pow(fac[m] * fac[n - m], mod - 2) % mod;
}
int main() {
scanf("%d%d", &n, &k);
for(int i = 1; i < n; i++) scanf("%d%d", &u, &v);
fac[0] = fac[1] = 1;
for(int i = 2; i < 377; i++) fac[i] = fac[i - 1] * i % mod;
if(k > n) k = n;
for(int i = 1; i <= k; i++) {
sum = (sum + Comb(n - 1, i - 1) * Comb(k, i) % mod * fac[i]) % mod;
}
printf("%lld\n", sum);
return 0;
} dfs序
总感觉以前听学长提起过,自己最近好像用过,遂翻了翻笔记,原来打Codeforces Round #629 (Div. 3)的E题时用到了,笔记地址http://www.kindkidll.com/index.php/archives/120/。
下图是一颗树加了时间戳的遍历结果,dfs序的好处在于把树形结构转化成了线性结构。假设要进行操作把某棵子树的结点加上某个值,求某棵子树结点的和,转化成线性结构后问题就变成线段树的区间更新和区间查询了。

京公网安备 11010502036488号