求树上所有连通块的权值第K大的和。
正解大概fft的本质吧qaq不会qaq
还好暴力可过。
我们考虑枚举每一个点,计算它对答案的贡献,即以这个点为第K大的连通块个数。为了避免重复,相等的我们也要钦定大小关系。
我们把所有点按点权从大到小排序,以这个点为根,之前的点标1,其余点标0.我们就是要求必须包含根的大小为K的连通块个数。可以背包dp解决。写的太丑会
O(nk2)
O
(
n
k
2
)
,其实可以
O(nk)
O
(
n
k
)
因为必须选根,每个点可以先强制从父亲转移过来,然后再更新到父亲上去。
总复杂度 O(n2k) O ( n 2 k )
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 1700
#define mod 64123
inline char gc(){
static char buf[1<<16],*S,*T;
if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int n,K,w[N],h[N],num=0,dp[N][N],b[N],a[N],ans=0;
struct edge{
int to,next;
}data[N<<1];
inline bool cmp(int x,int y){return w[x]>w[y];}
inline void inc(int &x,int y){x+=y;x%=mod;}
void dfs(int x,int Fa){
for(int i=1;i<=K;++i) dp[x][i]=dp[Fa][i-a[x]];
for(int i=h[x];i;i=data[i].next){
int y=data[i].to;if(y==Fa) continue;dfs(y,x);
}if(Fa) for(int i=1;i<=K;++i) inc(dp[Fa][i],dp[x][i]);
}
int main(){
// freopen("a.in","r",stdin);
n=read();K=read();read();
for(int i=1;i<=n;++i) w[i]=read(),b[i]=i;
sort(b+1,b+n+1,cmp);
for(int i=1;i<n;++i){
int x=read(),y=read();
data[++num].to=y;data[num].next=h[x];h[x]=num;
data[++num].to=x;data[num].next=h[y];h[y]=num;
}for(int i=1;i<=n;++i){
int x=b[i];a[x]=1;if(i<K) continue;dp[0][0]=1;
dfs(x,0);inc(ans,dp[x][K]*w[x]%mod);
}printf("%d\n",ans);
return 0;
}