联考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);
}