题目链接:http://codeforces.com/contest/1113/problem/F
题意:
给你n个点,问你能构建出多少棵好看的树。好看的树是这样定义的,对于树上的每条边,边的权值都不会超过m,同时点a和点b之间的距离正好为m,距离定义为这两点最短路上的边之和。
做法:
很明显是枚举点a和点b之间有多少个点,即对点a和b之间的点和以外的点分别计算。每一部分要计算的是位置分配信息和权值分配信息。
如果这两条边之间有x个点,那么选出这x个点并排列有种方法(位置),对这些点之间的边的选取则是对m进行隔板插空(权值),因为边权至少为1所以是在m-1个位置中放x个位置,即再乘。
对于这x个点之外的点,每个点都带一个权值可以为1~m的边,要乘上,位置信息则需要用到一个所谓的广义Cayley公式,这里的是计算对于n个点,分成k个连通块的分类数量,即组成一个k个根节点的森林的种数。
计算的公式为
然后就是水题了。。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=(int)1e9+7;
const int maxn=1000005;
ll fac[maxn],inv_fac[maxn];
ll quick(ll a,ll b){
ll ans=1;
while(b){
if(b&1) ans=ans*a%mod;
a=a*a%mod;
b/=2;
}
return ans;
}
void init(){
inv_fac[0]=fac[0]=1,fac[1]=inv_fac[1]=1;
for(int i=2;i<maxn;i++)
fac[i]=fac[i-1]*i%mod;
inv_fac[maxn-1]=quick(fac[maxn-1],mod-2);
for(int i=maxn-2;i>=0;i--)
inv_fac[i]=inv_fac[i+1]*(i+1)%mod;
}
ll C(ll n,ll m){
if(n<0||m<0||m>n) return 0;
if(n==m||m==0) return 1;
return fac[n]*inv_fac[n-m]%mod*inv_fac[m]%mod;
}
int n,m,a,b;
int main(){
init();
scanf("%d%d%d%d",&n,&m,&a,&b);
ll ans=0;
for(int i=0;i<=n-2;i++){
if(i>=m) break;
if(i==n-2) ans=(ans+C(m-1,i)*fac[i]%mod)%mod;
else ans=(ans+C(n-2,i)*fac[i]%mod*C(m-1,i)%mod*quick(m,n-2-i)%mod*(2+i)%mod*quick(n,n-(i+2)-1))%mod;
}
printf("%lld\n",ans);
return 0;
}
/*
5 15 1 5
3 3 1 3
8
4 2 1 3
*/