51nod-1677 treecnt
2016-12-02 20:19
302 查看
原题链接
1677 treecnt
基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题
收藏
关注
给定一棵n个节点的树,从1到n标号。选择k个点,你需要选择一些边使得这k个点通过选择的边联通,目标是使得选择的边数最少。
现需要计算对于所有选择k个点的情况最小选择边数的总和为多少。
样例解释:
一共有三种可能:(下列配图蓝色点表示选择的点,红色边表示最优方案中的边)
选择点{1,2}:至少要选择第一条边使得1和2联通。
选择点{1,3}:至少要选择第二条边使得1和3联通。
选择点{2,3}:两条边都要选择才能使2和3联通。
Input
Output
Input示例
Output示例
对于每条边只要算出它对答案的贡献次数就可以.假设一条边的两端有kk, n-kk个节点,那么这条边的贡献次数为C(n, k) - C(kk, k) - C(n-kk, k)
#include <cstdio>
#include <cmath>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#define MOD 1000000007
#define maxn 100005
using namespace std;
typedef long long ll;
vector<int> v[maxn];
ll p[maxn], d[maxn];
ll e;
int n, k;
ll solve(ll m){
ll ans = 1, t = MOD - 2;
while(t){
if(t&1)
(ans *= m) %= MOD;
(m *= m) %= MOD;
t >>= 1;
}
return ans;
}
ll f(int kk){
ll mm = p
* d[k] % MOD * d[n-k] % MOD;
if(k <= kk){
mm -= p[kk] * d[k] % MOD * d[kk-k] % MOD;
(mm += MOD) % MOD;
}
if(n - kk >= k){
mm -= p[n-kk] * d[k] % MOD * d[n-kk-k] % MOD;
(mm += MOD) %= MOD;
}
return mm;
}
int dfs(int j, int ff){
int kk = 1;
for(int i = 0; i < v[j].size(); i++){
int h = v[j][i];
if(h != ff){
kk += dfs(h, j);
}
}
(e += f(kk)) %= MOD;
return kk;
}
int main(){
// freopen("in.txt", "r", stdin);
int a, b;
scanf("%d%d", &n, &k);
p[0] = 1;
d[0] = 1;
for(int i = 1; i <= n; i++){
(p[i] = i * p[i-1]) %= MOD;
d[i] = solve(p[i]);
}
for(int i = 0; i < n - 1; i++){
scanf("%d%d", &a, &b);
v[a].push_back(b);
v[b].push_back(a);
}
dfs(1, -1);
printf("%I64d\n", e);
return 0;
}
1677 treecnt
基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题
收藏
关注
给定一棵n个节点的树,从1到n标号。选择k个点,你需要选择一些边使得这k个点通过选择的边联通,目标是使得选择的边数最少。
现需要计算对于所有选择k个点的情况最小选择边数的总和为多少。
样例解释:
一共有三种可能:(下列配图蓝色点表示选择的点,红色边表示最优方案中的边)
选择点{1,2}:至少要选择第一条边使得1和2联通。
选择点{1,3}:至少要选择第二条边使得1和3联通。
选择点{2,3}:两条边都要选择才能使2和3联通。
Input
第一行两个数n,k(1<=k<=n<=100000) 接下来n-1行,每行两个数x,y描述一条边(1<=x,y<=n)
Output
一个数,答案对1,000,000,007取模。
Input示例
3 2 1 2 1 3
Output示例
4
对于每条边只要算出它对答案的贡献次数就可以.假设一条边的两端有kk, n-kk个节点,那么这条边的贡献次数为C(n, k) - C(kk, k) - C(n-kk, k)
#include <cstdio>
#include <cmath>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#define MOD 1000000007
#define maxn 100005
using namespace std;
typedef long long ll;
vector<int> v[maxn];
ll p[maxn], d[maxn];
ll e;
int n, k;
ll solve(ll m){
ll ans = 1, t = MOD - 2;
while(t){
if(t&1)
(ans *= m) %= MOD;
(m *= m) %= MOD;
t >>= 1;
}
return ans;
}
ll f(int kk){
ll mm = p
* d[k] % MOD * d[n-k] % MOD;
if(k <= kk){
mm -= p[kk] * d[k] % MOD * d[kk-k] % MOD;
(mm += MOD) % MOD;
}
if(n - kk >= k){
mm -= p[n-kk] * d[k] % MOD * d[n-kk-k] % MOD;
(mm += MOD) %= MOD;
}
return mm;
}
int dfs(int j, int ff){
int kk = 1;
for(int i = 0; i < v[j].size(); i++){
int h = v[j][i];
if(h != ff){
kk += dfs(h, j);
}
}
(e += f(kk)) %= MOD;
return kk;
}
int main(){
// freopen("in.txt", "r", stdin);
int a, b;
scanf("%d%d", &n, &k);
p[0] = 1;
d[0] = 1;
for(int i = 1; i <= n; i++){
(p[i] = i * p[i-1]) %= MOD;
d[i] = solve(p[i]);
}
for(int i = 0; i < n - 1; i++){
scanf("%d%d", &a, &b);
v[a].push_back(b);
v[b].push_back(a);
}
dfs(1, -1);
printf("%I64d\n", e);
return 0;
}
相关文章推荐
- MySQL update Error Code: 1175
- matlab 控件之间通过GUI Data传递数据
- Java与C++面向对象不同点
- 关于企业号后台的一些零碎使用
- Java运行时异常与普通异常的区别
- 详解mysql数据库的左连接、右连接、内连接的区别
- xacml开源代码
- 堆排序原理及算法实现(最大堆)
- matlab—图像显示
- 新手学习网页布局的小技巧!
- [基础训练]数列排序
- 第一个linux驱动_读写设备文件(2)
- (第十三周)Final Review会议
- POJ 1201 Intervals 差分约束系统
- 测试开发之----给你的apk加上时间分片的log记录
- Android Volley完全解析(一),初识Volley的基本用法
- 第一个linux驱动_读写设备文件(1)
- 数据库读写分离
- POJ 3371
- 一个简单的逆向