考虑暴力的dp
fx,ifx,i 表示 xx 点权值为 的方案数,这个dp数组是有对称性的。
再观察一下可以发现,大于 n∗kn∗k 且小于 m−n∗k+1m−n∗k+1 的部分方案数是一样的
那么只要记录权值小于等于 n∗kn∗k 和权值大于等于 m−n∗k+1m−n∗k+1 的部分就行了
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const int N=110,P=1e9+7;
int t,n,m,k,cnt,G[N];
int f[N][2*N*N],g[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;
}
int tmp[N*N+N];
void pfs(int x,int p){
for(int i=G[x];i;i=E[i].nx){
int v=E[i].t;
if(v==p) continue; pfs(v,x);
for(int j=1;j<=m;j++) tmp[j]=(tmp[j-1]+f[v][j])%P;
for(int j=1;j<=m;j++)
f[x][j]=1LL*f[x][j]*((g[v]-tmp[min(j+k-1,m)])%P+tmp[max(j-k,0)])%P;
}
for(int i=1;i<=m;i++) g[x]=(g[x]+f[x][i])%P;
}
void dfs(int x,int p){
for(int i=G[x];i;i=E[i].nx){
int v=E[i].t;
if(v==p) continue;
dfs(v,x);
for(int j=1;j<=n*k;j++) tmp[j]=(tmp[j-1]+f[v][j])%P;
for(int j=n*k+1;j<=n*k+k;j++) tmp[j]=(tmp[j-1]+f[v][n*k])%P;
for(int j=1;j<=n*k;j++){
f[x][j]=1LL*f[x][j]*((g[v]-tmp[j+k-1])%P+tmp[max(j-k,0)])%P;
}
}
for(int i=1;i<=n*k;i++) g[x]=(g[x]+2LL*f[x][i])%P;
g[x]=(g[x]+1LL*f[x][n*k]*(m-2*n*k))%P;
}
inline int Pow(int x,int y){
int ret=1;
for(;y;y>>=1,x=1LL*x*x%P) if(y&1) ret=1LL*ret*x%P;
return ret;
}
int main(){
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
scanf("%d",&t);
while(t--){
cnt=0;
memset(tmp,0,sizeof(tmp));
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++){
G[i]=g[i]=0;
for(int j=1;j<=m && j<=2*n*k;j++) f[i][j]=1;
}
for(int i=1,x,y;i<n;i++)
scanf("%d%d",&x,&y),addedge(x,y);
if(k==0){
printf("%d\n",Pow(m,n)); continue;
}
if(2*n*k>=m) pfs(1,0);
else dfs(1,0);
printf("%d\n",(g[1]+P)%P);
}
return 0;
}