CF995F Cowmpany Cowmpensation < 树形DP+多项式插值 >

Problem

Cowmpany Cowmpensation

Time  Limit:  2  seconds\mathrm{Time\;Limit:\;2\;seconds}
Memory  Limit:  256  megabytes\mathrm{Memory\;Limit:\;256\;megabytes}

Description

Allen, having graduated from the MOO Institute of Techcowlogy (MIT), has started a startup! Allen is the president of his startup. He also hires n1n-1 other employees, each of which is assigned a direct superior. If uu is a superior of vv and vv is a superior of ww then also uu is a superior of ww. Additionally, there are no uu and vv such that uu is the superior of vv and vv is the superior of uu. Allen himself has no superior. Allen is employee number 11, and the others are employee numbers 22 through nn.
Finally, Allen must assign salaries to each employee in the company including himself. Due to budget constraints, each employee’s salary is an integer between 11 and DD. Additionally, no employee can make strictly more than his superior.
Help Allen find the number of ways to assign salaries. As this number may be large, output it modulo 109+710^9+7.

Input

The first line of the input contains two integers nn and DD (1n30001\le n\le3000, 1D1091\le D\le10^9).
The remaining n1n-1 lines each contain a single positive integer, where the ithi^{th} line contains the integer pip_i (1pii1\le p_i\le i). pip_i denotes the direct superior of employee i+1i+1.

Output

Output a single integer: the number of ways to assign salaries modulo 109+710^9+7.

Example

Input #1

1
2
3
3 2
1
1

Output #1

1
5

Input #2

1
2
3
3 3
1
2

Output #2

1
10

Input #3

1
2
2 5
1

Output #3

1
15

Note

In the first sample case, employee 22 and 33 report directly to Allen. The three salaries, in order, can be (1,1,1)(1,1,1), (2,1,1)(2,1,1), (2,1,2)(2,1,2), (2,2,1)(2,2,1) or (2,2,2)(2,2,2).
In the second sample case, employee 22 reports to Allen and employee 33 reports to employee 22. In order, the possible salaries are (1,1,1)(1,1,1), (2,1,1)(2,1,1), (2,2,1)(2,2,1), (2,2,2)(2,2,2), (3,1,1)(3,1,1), (3,2,1)(3,2,1), (3,2,2)(3,2,2), (3,3,1)(3,3,1), (3,3,2)(3,3,2), (3,3,3)(3,3,3).

标签:树形DP 多项式插值

Translation

题目大意:给定一棵根为11的树,需要给每个结点一个权值,使得父亲的权值不小于儿子的权值,并且所有权值均不大于DD。求可行方案数并输出其模109+710^9+7的值。

Solution

不考虑数据范围,可以先想到一个O(nD)O(nD)的暴力DP\mathrm{DP}做法。
f[u][i]f[u][i]表示对于结点uu及其子树,ii的权值为uu时可行方案数,那么有转移方程:

f[u][i]=uvEjif[v][j]f[u][i]=\prod_{(u\to v)\in E}\sum_{j\le i}f[v][j]

用前缀和优化一下,令g[u][i]=j=0if[u][j]g[u][i]=\sum_{j=0}^{i}f[u][j],那么有

f[u][i]=uvEg[v][i]f[u][i]=\prod_{(u\to v)\in E}g[v][i]

最终答案为g[1][D]g[1][D],显然复杂度O(nD)O(nD)TLE\mathrm{TLE}

发现一个性质:令xx的子树大小为szxsz_x,将f[x][],g[x][]f[x][],g[x][]作为两个多项式fx,gxf_x,g_x看待,那么fuf_u是一个szu1sz_u-1次多项式,gug_u是一个szusz_u次多项式。
这个性质可以用归纳法证明:

  • szu=1sz_u=1时,即uu为叶子结点时,fu(x)=1f_u(x)=1gu(x)=xg_u(x)=x,满足性质
  • szu>1sz_u>1时,假设该性质对于1(szu1)1\sim(sz_u-1)均成立,那么对于uu的儿子vvfvf_v为一个szv1sz_v-1次多项式,gvg_v为一个szvsz_v次多项式。由于fu(x)=(uv)Egv(x)f_u(x)=\prod_{(u\to v)\in E}g_v(x),可知fuf_u为一个szv\sum sz_v次多项式,即szu1sz_u-1次多项式。对于每一个x[0,szu]x\in[0,sz_u],都对应一个fu(x)f_u(x)为一个szu1sz_u-1次多项式,于是共有szu+1sz_u+1个点值,对应一个szusz_u次多项式,即gug_u为一个szusz_u次多项式。

由此可知,g1g_1为一个nn次多项式,只需求得g1(0)g1(n)g_1(0)\sim g_1(n)即可确定此多项式,而所求为g1(D)g_1(D),运用特殊多项式在整点上线性插值的方法可以在O(n)O(n)时间内求得答案。总复杂度O(n2+n)O(n^2+n)

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <bits/stdc++.h>
#define MAX_N 3000
#define P 1000000007
using namespace std;
typedef long long lnt;
template <class T> inline void read(T &x) {
x = 0; int c = getchar(), f = 1;
for (; !isdigit(c); c = getchar()) if (c == 45) f = -1;
for (; isdigit(c); c = getchar()) (x *= 10) += f*(c-'0');
}
int n, m;
vector <int> G[MAX_N+5];
lnt f[MAX_N+5][MAX_N+5];
lnt fac[MAX_N+5], inv[MAX_N+5];
void init(int n) {
fac[0] = inv[0] = inv[1] = 1;
for (int i = 1; i <= n; i++) fac[i] = fac[i-1]*i%P;
for (int i = 2; i <= n; i++) inv[i] = (P-P/i*inv[P%i]%P)%P;
for (int i = 2; i <= n; i++) inv[i] = inv[i]*inv[i-1]%P;
}
void DFS(int u) {
for (int x = 1; x <= n; x++) f[u][x] = 1;
for (int i = 0; i < (int)G[u].size(); i++) {
int v = G[u][i]; DFS(v);
for (int x = 1; x <= n; x++)
f[u][x] = f[u][x]*f[v][x]%P;
}
for (int x = 1; x <= n; x++)
f[u][x] = (f[u][x]+f[u][x-1])%P;
}
#define getL(i) (i < n ? pre[n-i-1] : 1)
#define getR(i) (i > 0 ? suc[n-i+1] : 1)
lnt Poly_Inter() {
lnt ret = 0;
lnt pre[MAX_N+5], suc[MAX_N+5]; pre[0] = m-n, suc[n] = m;
for (int i = 1; i <= n-1; i++) pre[i] = pre[i-1]*(m-n+i)%P;
for (int i = n-1; i >= 1; i--) suc[i] = suc[i+1]*(m-n+i)%P;
for (int i = 0, c = (n&1) ? -1 : 1; i <= n; i++, c = -c)
ret = (ret+c*getL(i)*getR(i)%P*inv[i]%P*inv[n-i]%P*f[1][i]%P)%P;
return (ret+P)%P;
}
int main() {
read(n), read(m), init(n);
for (int i = 2, x; i <= n; i++)
read(x), G[x].push_back(i);
DFS(1), printf("%lld\n", Poly_Inter());
return 0;
}