# [Heoi 2013] bzoj3167 SAO [树形dp]

Description:

Solution:
$dp\left[u\right]\left[i\right]$$dp[u][i]$表示第$u$$u$个点在子树中排名为$i$$i$的方案数,那么枚举新加入的点有多少个比$u$$u$小。

$dp\left[u\right]\left[j+k\right]+=dp\left[u\right]\left[j\right]\ast C\left(k+j-1,k\right)\ast C\left(sz\left[u\right]+sz\left[v\right]-j-k,sz\left[v\right]-k\right)\ast \sum _{i=1}^{k}dp\left[v\right]\left[i\right]$$dp[u][j+k]+=dp[u][j]*C(k+j-1,k)*C(sz[u]+sz[v]-j-k,sz[v]-k)*\sum_{i=1}^{k}{dp[v][i]}$

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1005, P = 1e9 + 7;
struct edge {
int nxt, to, w;
} e[maxn * 2];
int n, cnt = 1;
int h[maxn], sz[maxn];
long long dp[maxn][maxn], sum[maxn][maxn], c[maxn][maxn], tmp[maxn];
void link(int u, int v, int w) {
e[++cnt].nxt = h[u];
h[u] = cnt;
e[cnt].to = v;
e[cnt].w = w;
}
void dfs(int u, int f) {
sz[u] = 1;
dp[u][1] = 1;
sum[u][1] = 1;
for(int i = h[u]; i; i = e[i].nxt) {
int v = e[i].to;
if(v != f) {
dfs(v, u);
memset(tmp, 0, sizeof(tmp));
for(int j = sz[u]; ~j; --j) {
for(int k = sz[v]; ~k; --k) {
tmp[j + k] = (tmp[j + k] + dp[u][j] * (e[i].w > 0 ? sum[v][k] : (sum[v][sz[v]] - sum[v][k] + P) % P) % P * c[k + j - 1][k] % P * c[sz[u] + sz[v] - j - k][sz[v] - k] % P) % P;
}
}
sz[u] += sz[v];
for(int j = 1; j <= sz[u]; ++j) {
dp[u][j] = tmp[j];
}
}
}
for(int i = 1; i <= sz[u]; ++i) {
sum[u][i] = (sum[u][i - 1] + dp[u][i]) % P;
}
}
int main() {
int T;
scanf("%d", &T);
c[0][0] = 1;
for(int i = 1; i < maxn; ++i) {
c[i][0] = 1;
for(int j = 1; j <= i; ++j) {
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % P;
}
}
while(T--) {
cnt = 1;
memset(h, 0, sizeof(h));
memset(dp, 0, sizeof(dp));
memset(sum, 0, sizeof(sum));
scanf("%d", &n);
for(int i = 1; i < n; ++i) {
int u, v, w;
char C[10];
scanf("%d%s%d", &u, C, &v);
++u;
++v;
if(C[0] == '>') {
w = 1;
} else {
w = -1;
}
}
dfs(1, 0);
printf("%lld\n", sum[1][n]);
}
return 0;
}

• 广告
• 抄袭
• 版权
• 政治
• 色情
• 无意义
• 其他

120