51Nod - 1677 treecnt

Discription

给定一棵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取模。

Sample Input

3 2
1 2
1 3

Sample Output

4


直接考虑每条边在选哪些点的时候会被选就行了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=100000,ha=1000000007;
int jc[maxn+5],ni[maxn+5],n,m,siz[maxn+5],T,ans;
int hd[maxn+5],ne[maxn*2+5],to[maxn*2+5],num;
inline void addline(int x,int y){ to[++num]=y,ne[num]=hd[x],hd[x]=num;}
inline int add(int x,int y){ x+=y; return x>=ha?x-ha:x;}
inline int ksm(int x,int y){ int an=1; for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha; return an;}
inline int C(int x,int y){ return x<y?0:jc[x]*(ll)ni[y]%ha*(ll)ni[x-y]%ha;}
inline void init(){
	jc[0]=1; for(int i=1;i<=maxn;i++) jc[i]=jc[i-1]*(ll)i%ha;
	ni[maxn]=ksm(jc[maxn],ha-2); for(int i=maxn;i;i--) ni[i-1]=ni[i]*(ll)i%ha;
}

void dfs(int x,int fa){
	siz[x]=1;
	for(int i=hd[x];i;i=ne[i]) if(to[i]!=fa) dfs(to[i],x),siz[x]+=siz[to[i]];
	if(fa) ans=add(ans,add(T,ha-add(C(siz[x],m),C(n-siz[x],m))));
}

int main(){
	int uu,vv; init();
	scanf("%d%d",&n,&m),T=C(n,m);
	for(int i=1;i<n;i++){
		scanf("%d%d",&uu,&vv);
		addline(uu,vv),addline(vv,uu);
	}
	dfs(1,0),printf("%d\n",ans);
	return 0;
}

  

 
posted @ 2018-04-24 16:23  蒟蒻JHY  阅读(142)  评论(0编辑  收藏  举报