设 fi f i 表示选出的联通块第 k k 大的值大于等于 的方案数
那么答案就是 ∑wi=1i(fi−fi+1)=∑wi=1fi ∑ i = 1 w i ( f i − f i + 1 ) = ∑ i = 1 w f i
枚举 i i ,把权值大于等于 的点标记为 1 1 ,否则标记为 ,那么 fi f i 就是树上包含至少 k k 个 的联通块的个数,树形DP一下就可以了
这样复杂度是 O(n3) O ( n 3 ) 的,时限这么大就不虚…
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=2010,P=64123;
int n,m,w,cnt,G[N],b[N],a[N],size[N],f[N][N];
struct edge{
int t,nx;
}E[N<<1];
inline void addedge(int x,int y){
E[++cnt].t=y; E[cnt].nx=G[x]; G[x]=cnt;
E[++cnt].t=x; E[cnt].nx=G[y]; G[y]=cnt;
}
inline void dp(int x,int p){
size[x]=b[x];
int *F=f[x];
for(int j=0;j<=n;j++) f[x][j]=0;
F[b[x]]=1;
for(int i=G[x];i;i=E[i].nx)
if(E[i].t!=p){
dp(E[i].t,x);
static ll tmp[N]; int *G=f[E[i].t];
for(int j=0;j<=size[x]+size[E[i].t];j++) tmp[j]=F[j];
for(int j=0;j<=size[x];j++)
for(int k=0;k<=size[E[i].t];k++)
tmp[j+k<m?j+k:m]+=1LL*F[j]*G[k];
size[x]+=size[E[i].t]; size[x]=size[x]<m?size[x]:m;
for(int j=0;j<=size[x];j++) F[j]=tmp[j]%P;
}
}
int main(){
scanf("%d%d%d",&n,&m,&w);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1,x,y;i<n;i++)
scanf("%d%d",&x,&y),addedge(x,y);
int ans=0,lst=0,lstans=0;
for(int i=1;i<=w;i++){
int tot=0;
for(int j=1;j<=n;j++) b[j]=(a[j]>=i),tot+=b[j];
if(tot<m) continue;
if(tot==lst){
ans=(ans+lstans)%P; continue;
}
lst=tot; lstans=0;
dp(1,0);
for(int j=1;j<=n;j++)
lstans=(lstans+f[j][m])%P;
ans=(ans+lstans)%P;
}
printf("%d\n",ans);
return 0;
}