题目
Description
Input
Output
一行一个整数表示题意描述中的式子的值。
Sample Input
样例 1输入:
3
1 2
样例 2输入:
5
1 2 3 2
样例 3输入:
9
1 2 1 2 5 4 7 8
Sample Output
样例 1输出:
10
样例 2输出:
816
样例 3输出:
6580992
Data Constraint
Hint
思路
题目要求lca的dep的乘积和,考虑把这个dep摊到lca的每一个祖先上。
设f[i][j]表示i为根的子树里,在下面合并完后,还剩j段的方案数。该状态段与段之间的顺序没有确
定。
f的转移:
每一次先把子树的段继承过来(子树背包实现),最后在这个点上合并段,合并段的系数可以预处理一个g[i][j] 表示i 段合并成j段的方案数,由 g[i]可以递推出g[i+1]。
代码
#include<bits/stdc++.h>
#define maxn 505
#define ll long long
#define mo 1000000007
using namespace std;
int n,fa[maxn],sz[maxn];
int em,e[maxn],nx[maxn],ls[maxn];
ll mul[maxn][maxn],f[maxn][maxn],g[maxn];
ll h[maxn][maxn][maxn],s[maxn*2];
void ins(int x,int y){
em++; e[em]=y; nx[em]=ls[x]; ls[x]=em;
}
void dfs(int x,int dep){
for(int i=ls[x];i;i=nx[i]) dfs(e[i],dep+1);
sz[x]=1,f[x][1]=1;
for(int i=ls[x];i;i=nx[i]) {
int y=e[i];
memset(g,0,sizeof(g));
for(int j=1;j<=sz[x];j++) for(int k=1;k<=sz[y];k++) for(int l=max(1,j-k);l<=j+k;l++)
g[l]+=h[j][k][l]%mo*f[x][j]%mo*f[y][k]%mo*mul[dep][k-(l-j)]%mo;
sz[x]+=sz[y];
for(int j=1;j<=sz[x];j++) f[x][j]=g[j]%mo;
}
}
void pre(){
h[0][0][0]=1;
for(int k=1;k<=n;k++) {
memset(s,0,sizeof(s));
for(int i=0;i<=n;i++) for(int j=0;i+j<=n;j++){
if (i+j>=k) {
h[i][j][k]=s[i-j+n]*2+s[i-j+n-1]+s[i-j+n+1];
if (h[i][j][k]>1e15) h[i][j][k]%=mo;
}
if (h[i][j][k-1]) s[i-j+n]+=h[i][j][k-1];
}
}
}
int main()
{
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
scanf("%d",&n);
for(int i=2;i<=n;i++) scanf("%d",&fa[i]),ins(fa[i],i);
for(int i=1;i<=n;i++)
{
mul[i][0]=1;
for(int j=1;j<=n;j++) mul[i][j]=mul[i][j-1]*i%mo;
}
pre();
dfs(1,1);
printf("%lld",f[1][1]);
}