[Heoi 2013] bzoj3167 SAO [树形dp]

Description:
一棵树,每条边上有一个不等号,求每个点填一个排列的数量。


Solution:
dp[u][i]表示第u个点在子树中排名为i的方案数,那么枚举新加入的点有多少个比u小。
对于u<v的情况,有
dp[u][j+k]+=dp[u][j]C(k+j1,k)C(sz[u]+sz[v]jk,sz[v]k)i=1kdp[v][i]
枚举了v中有多少个比u小,乘上对应v所有可能的排名情况,然后把vu小的那部分和之前比u小的做归并,即C(k+j1,k),后面则是后面一部分做归并。

#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;
            }
            link(u, v, w);
            link(v, u, -w);
        }
        dfs(1, 0);
        printf("%lld\n", sum[1][n]);
    }
    return 0;
}
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页