51nod 1677 treecnt(树形 dp,逆元,贡献)
发布日期:2021-11-02 09:49:01 浏览次数:1 分类:技术文章

本文共 1780 字,大约阅读时间需要 5 分钟。

1677 treecnt

给定一棵n个节点的树,从1到n标号。选择k个点,你需要选择一些边使得这k个点通过选择的边联通,目标是使得选择的边数最少。

现需要计算对于所有选择k个点的情况最小选择边数的总和为多少。

样例解释:

一共有三种可能:(下列配图蓝色点表示选择的点,红色边表示最优方案中的边)

选择点{1,2}:至少要选择第一条边使得1和2联通。
在这里插入图片描述
选择点{1,3}:至少要选择第二条边使得1和3联通。
在这里插入图片描述
选择点{2,3}:两条边都要选择才能使2和3联通。
在这里插入图片描述

输入

第一行两个数n,k(1<=k<=n<=100000)

接下来n-1行,每行两个数x,y描述一条边(1<=x,y<=n)

输出

一个数,答案对1,000,000,007取模。

输入样例1

3 2

1 2
1 3

输出样例1

4

输入样例2

10 4

4 7
7 10
10 2
2 8
8 3
3 9
9 1
1 5
5 6

输出样例2

1386

#include 
#define ll long longusing namespace std;const int maxn = 100005;const int mod = 1e9 + 7;struct node {
int v, next;} tree[maxn * 2];int dp[maxn];int vis[maxn];int head[maxn * 2];ll n, k, num, answer = 0;// cbk[i]为C n kll cbk[maxn];ll QuickPow(ll x, ll N) {
ll res = x; ll ans = 1; while (N) {
if (N & 1) {
ans = ans * res % mod; } res = res * res % mod; N = N >> 1; } return ans;}// 1/all getInv(ll a) {
return QuickPow(a, mod - 2);}void add(int x, int y) {
tree[num].v = y; tree[num].next = head[x]; head[x] = num++;}void dfs(int u) {
vis[u] = 1; dp[u] = 1; for (int i = head[u]; i != -1; i = tree[i].next) {
int v = tree[i].v; if (!vis[v]) {
dfs(v); dp[u] += dp[v]; } } // 要选k个点,这条边连接的两个连通块大小为x,y的话,贡献为C(n,k)-C(x,k)-C(y,k) answer = (answer + cbk[n] - cbk[dp[u]] - cbk[n - dp[u]] + 2 * mod) % mod;}int main() {
cin >> n >> k; memset(head, -1, sizeof(head)); memset(vis, 0, sizeof(vis)); for (int i = 1; i < n; i++) {
int a, b; cin >> a >> b; add(a, b); add(b, a); } cbk[k] = 1; for (int i = k + 1; i <= n; i++) {
cbk[i] = ((cbk[i - 1] * i) % mod * getInv(i - k)) % mod; } dfs(1); cout << answer << endl; return 0;}

转载地址:https://blog.csdn.net/weixin_43820352/article/details/111665971 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:P5905 【模板】Johnson 全源最短路
下一篇:默认Date时间格式修改(Java 工具类)

发表评论

最新留言

逛到本站,mark一下
[***.202.152.39]2024年03月31日 20时56分49秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章