Problem
Description
Input
Output
Sample Input
3
2 2 0
1 2
3 3 2
1 3
1 2
3 3 1
1 2
2 3
Sample Output
4
2
12
Data Constraint
Hint
Solution
果断树形DP。
首先我们先过前20%和40%数据。
设
Fx,y
表示x号点取y所满足的方案数。
易得方程
Fx,y=Πv∈sonxΣFv,i当且仅当(|i−y|≥k)
对于 40%数据,可以发现有一段 Fv,i 连续相等。
于是我们维护一个前缀和就行了。
接下来我们该考虑如何 切掉这题。
我们发现,同一个 x <script type="math/tex" id="MathJax-Element-270">x</script>对应的DP值是对称的。然后中间有一段DP值是相同的。
然后我们分类讨论去求其值就行了。
Code
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#define N 110
#define LL long long
#define mo 1000000007
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
LL a[N][N],b[N][N],deep[N],d[N],f[N][30010],sum[N][30010];
LL _,mx,i,j,n,m,k,x,y,wz,tot,ans;
bool bz[N];
LL ges(LL x,LL j)
{
if (j<=wz) return sum[x][j];else
if (j<=m-wz) return (sum[x][wz]+(j-wz)*f[x][wz+1])%mo;else
{
LL temp;
temp=(sum[x][wz]-sum[x][m-j]+mo)%mo;
temp=(temp+(sum[x][wz]+(m-wz*2+mo)*f[x][wz+1])%mo)%mo;
return temp;
}
}
LL ksm(LL x,LL p)
{
LL s=1;
while (p)
{
if (p%2) s=(s*x)%mo;
x=(x*x)%mo;
p/=2;
}
return s;
}
void dg(LL k,LL fa)
{
LL i;
fo(i,1,a[k][0])
{
if (a[k][i]==fa) continue;
deep[a[k][i]]=deep[k]+1;
dg(a[k][i],k);
}
}
void dfs(LL x)
{
LL i,j,y,now,p;
bz[x]=1;
fo(i,1,b[x][0])
{
if (bz[b[x][i]]) continue;
dfs(b[x][i]);
fo(y,1,wz+1)
{
p=0;
if (y-k>=0) p=ges(b[x][i],y-k);
if (y+k<=m) p=(p+ges(b[x][i],m)-ges(b[x][i],y+k-1)+mo)%mo;
if (!k) p=(p-ges(b[x][i],y)+ges(b[x][i],y-1)+mo)%mo;
f[x][y]=(f[x][y]*p)%mo;
}
sum[x][0]=0;
fo(y,1,wz+1) sum[x][y]=(sum[x][y-1]+f[x][y])%mo;
}
}
int main()
{
freopen("label.in","r",stdin);
freopen("label.out","w",stdout);
scanf("%lld",&_);
while (_--)
{
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(deep,0,sizeof(deep));
memset(bz,0,sizeof(bz));
scanf("%lld%lld%lld",&n,&m,&k);
if (m<=9901) wz=m;else wz=(n-1)*k+1;
fo(i,1,n-1)
{
scanf("%lld%lld",&x,&y);
a[x][++a[x][0]]=y;
a[y][++a[y][0]]=x;
}
dg(1,0);
fo(i,1,n) fo(j,1,30009) f[i][j]=1,sum[i][j]=sum[i][j-1]+f[i][j];
fo(i,1,n)
fo(j,1,a[i][0])
if (deep[i]<deep[a[i][j]]) b[i][++b[i][0]]=a[i][j];
dfs(1);
ans=ges(1,m);
printf("%lld\n",ans);
}
}