联考20200730 T1 小B的班级


分析:
考虑一条边某一侧有\(A\)个男生,\(B\)个女生,那么这条边的贡献为\(min(A+B,2m-A-B)len\)
怎么快速算呢?
发现能放\(O(nm)\)过,直接暴力枚举\(A+B\)这种贡献的方案数就好了
预处理一下幂和组合数
(我没有预处理组合数然后被卡常了QAQ

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<string>

#define maxn 100005
#define INF 0x3f3f3f3f
#define MOD 1000000007

using namespace std;

inline long long getint()
{
	long long num=0,flag=1;char c;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
	return num*flag;
}

int n,m;
int fir[maxn],nxt[maxn],to[maxn],len[maxn],cnt;
int sz[maxn];
int fac[maxn],inv[maxn];
int p1[maxn],p2[maxn];
int M[maxn];
int ans;

inline void newnode(int u,int v,int w)
{to[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt,len[cnt]=w;}
inline int C(int p,int q)
{return 1ll*fac[p]*inv[q]%MOD*inv[p-q]%MOD;}

inline void dfs(int u,int fa)
{
	sz[u]=1;
	for(int i=fir[u];i;i=nxt[i])if(to[i]!=fa)
	{
		dfs(to[i],u),sz[u]+=sz[to[i]];
		p1[0]=p2[0]=1;
		for(int j=1;j<=2*m;j++)
		{
			p1[j]=1ll*p1[j-1]*sz[to[i]]%MOD;
			p2[j]=1ll*p2[j-1]*(n-sz[to[i]])%MOD;
		}
		for(int j=1;j<=m;j++)ans=(ans+1ll*M[j]*p1[j]%MOD*p2[2*m-j]%MOD*j%MOD*len[i])%MOD;
		for(int j=m+1;j<2*m;j++)ans=(ans+1ll*M[j]*p1[j]%MOD*p2[2*m-j]%MOD*(2*m-j)%MOD*len[i])%MOD;
	}
}

int main()
{
	n=getint(),m=getint();
	for(int i=1;i<n;++i)
	{
		int u=getint(),v=getint(),w=getint();
		newnode(u,v,w),newnode(v,u,w);
	}
	fac[0]=fac[1]=inv[0]=inv[1]=1;
	for(int i=2;i<=2*m;i++)fac[i]=1ll*fac[i-1]*i%MOD;
	for(int i=2;i<=2*m;i++)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
	for(int i=2;i<=2*m;i++)inv[i]=1ll*inv[i]*inv[i-1]%MOD;
	for(int i=0;i<=2*m;i++)M[i]=C(2*m,i);
	dfs(1,0);
	printf("%d\n",ans);
}

posted @ 2020-07-30 17:29  Izayoi_Doyo  阅读(196)  评论(0编辑  收藏  举报