Description

在幻想乡白玉楼有一棵终年不开花的樱树叫西行妖,西行寺幽幽子曾经为了让它开花而大量收集春度,然后被城管教训了一顿…
现在,幽幽子得到城管的允许,收集了S点春度,让西行妖重新开花。
西行妖可以被看成是一棵有n个节点的树,每个叶子节点被分配了1点春度就能开花(幽幽子不会无意义地使用她的春度,于是最多只会给同一个叶子节点分配1点春度),对于非叶子节点i,如果它有至少有1个儿子开花,那么节点i能开花。
据说,西行妖的花开满之时,幽幽子会复活。但是城管只给了S点春度(S≤20),所以幽幽子这次是抱着娱乐的心态种树的。
如果西行妖有至少m个节点开花,那么幽幽子认为它是美丽的。现在幽幽子想知道,有多少种方案,使西行妖是美丽的(答案对10^9+7取模)。
注意:幽幽子不一定会把S点春度都分配完。

Solution

一看就知道是一个DP题

设f[i][j][k]表示在第i个叶子节点,用了j个春度,k个节点开了花
转移很显然f[i][j][k]=∑f[l][j−1][k−(deep[i]−deep[lca(i,l)])]
如果叶子节点乱序的话,会对DP造成影响,所以叶子节点最好用dfs序来排一个序。
O(n3s)70分

优化

如果直接用dfs序的顺序来转移,那么一颗子树中lca的深度是递增的。
为了运用这个性质方便转移,所以我们设s[j][k][d]=∑f[l][j][k],d表示所有lca(i,l)深度为d,光用s还不能转移,观察一下方程,再设cnt[j][k−d]=∑s[j][k][d],那么f[i][j][k]=cnt[j−1][k−deep[i]]
我们只要在访问每个叶子节点的时候更新f,并用更新之后的f来更新s和cnt。
每次搜完i的所有子节点时,再向上传递后,原来lca深度为d,现在变成了d-1,所有还要把s[j][k][d-1]的值更新,并清空s[i][]j[d],并继续更新cnt数组。

xdl司机春度是什么鬼

xdl:不知道,番上的翻译是这样的。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
#define rep(i,a) for(i=first[a];i;i=next[i])
using namespace std;
const int maxn=1007,mo=1000000007;
int i,j,k,l,t,n,m,s;
bool bz[maxn];
int last[maxn*2],first[maxn*2],next[maxn*2],num,ans;
int f[maxn][22][maxn],deep[maxn],df[maxn],a[maxn],dfn,pp;
int cnt[maxn][maxn*2],ss[22][maxn][maxn],tot;
struct node{
int x,y;
}b[maxn];
bool cmp(node x,node y){
return x.y<y.y;
}
void add(int x,int y){
last[++num]=y,next[num]=first[x],first[x]=num;
}
int lca(int x,int y){
int i,j;
if(deep[x]<deep[y])swap(x,y);
fod(i,20,0)if(deep[f[x][i][j]]>deep[y])x=f[x][i][j];
if(deep[x]!=deep[y])x=f[x][0][j];
fod(i,20,0)if(f[x][i][j]!=f[y][i][j])x=f[x][i][j],y=f[y][i][j];
if(x!=y)return f[x][0][j];return x;
}
void dfs(int x,int y){
int i,j;
deep[x]=deep[y]+1;
rep(i,x)if(last[i]!=y)dfs(last[i],x);
if(!first[x]){
++tot;
fo(i,1,s){
fo(j,deep[x],n)(f[tot][i][j]=cnt[i-1][j-deep[x]])%=mo;
}
fo(i,1,s){
fo(j,1,n)if(f[tot][i][j])(ss[i][j][deep[x]]+=f[tot][i][j])%=mo;
}
fo(i,1,s){
fo(j,deep[x],n)if(f[tot][i][j])(cnt[i][j-deep[x]]+=f[tot][i][j])%=mo;
}
}
fo(i,1,s){
fo(j,deep[x],n)if(ss[i][j][deep[x]]){
(cnt[i][j-deep[x]]-=ss[i][j][deep[x]])%=mo;
(cnt[i][j-deep[x]+1]+=ss[i][j][deep[x]])%=mo;
}
}
fo(i,1,s){
fo(j,1,n)if(ss[i][j][deep[x]]){
(ss[i][j][deep[x]-1]+=ss[i][j][deep[x]])%=mo;
ss[i][j][deep[x]]=0;
}
}
}
int main(){
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
scanf("%d%d%d",&n,&m,&s);
fo(i,2,n)scanf("%d",&k),add(k,i);cnt[0][0]=1;
dfs(1,0);
fo(i,1,tot)fo(j,1,s)fo(k,m,n)if(f[i][j][k])ans=(ans+f[i][j][k])%mo;
printf("%d\n",ans);
}