1. 程式人生 > >[BZOJ3167][Heoi2013]Sao

[BZOJ3167][Heoi2013]Sao

賦值 next sum void code n) sam add sta

3167: [Heoi2013]Sao

Time Limit: 30 Sec Memory Limit: 256 MB Submit: 188 Solved: 83 [Submit][Status][Discuss]

Description

WelcometoSAO(StrangeandAbnormalOnline)。這是一個VRMMORPG,含有n個關卡。但是,挑戰不同關卡的順序是一 個很大的問題。有n–1個對於挑戰關卡的限制,諸如第i個關卡必須在第j個關卡前挑戰,或者完成了第k個關卡才 能挑戰第l個關卡。並且,如果不考慮限制的方向性,那麽在這n–1個限制的情況下,任何兩個關卡都存在某種程 度的關聯性。即,我們不能把所有關卡分成兩個非空且不相交的子集,使得這兩個子集之間沒有任何限制。

Input

第一行,一個整數T,表示數據組數。對於每組數據,第一行一個整數n,表示關卡數。接下來n–1行,每行為“i sign j”,其中0≤i,j≤n–1且i≠j,sign為“<”或者“>”,表示第i個關卡必須在第j個關卡前/後完成。 T≤5,1≤n≤1000

Output

對於每個數據,輸出一行一個整數,為攻克關卡的順序方案個數,mod1,000,000,007輸出。

Sample Input

5
10
5 > 8
5 > 6
0 < 1
9 < 4
2 > 5
5 < 9
8 < 1
9 > 3
1 < 7
10
6 > 7
2 > 0
9 < 0
5 > 9
7 > 0
0 > 3
7 < 8
1 < 2
0 < 4
10
2 < 0
1 > 4
0 > 5
9 < 0
9 > 3
1 < 2
4 > 6
9 < 8
7 > 1
10
0 > 9
5 > 6
3 > 6
8 < 7
8 > 4
0 > 6
8 > 5
8 < 2
1 > 8
10
8 < 3
8 < 4
1 > 3
1 < 9
3 < 7
2 < 8
5 > 2
5 < 6
0 < 9

Sample Output

2580
3960
1834
5208
3336
可以發現把關系看成邊的話這是一顆樹 設$f[i][j]$表示在以$i$為根的子數中,根節點是第$j$大 那麽考慮每次和一顆子樹的答案合並(顯然合並子樹的順序不影響答案) 對於每一個$f[u][j]$來說,當它在合並時孩子$v$時 先不考慮$u$和$v$兩顆樹本身的以及$u$和$v$之間的大小關系,那麽可以 枚舉子樹中前$k$小的點比根小,那麽這一步就有$C_{j+k-1}^{k}*C_{siz[u]+siz[v]-j-k}^{siz[v]-k}$種方案 這是因為把一個子樹從小到大攤成一個序列後 $u$前面有$j+k-1$個位置放點,其中選$k$個給$v$,$u$後面有&siz[u]+siz[v]-j-k&個位置放點,其中選$siz[v]-k$個給孩子
然後要考慮$u$和$v$兩顆子樹本身之間的關系 以$u$在$v$後面為例 $v$肯定在插入$u$之前的那$k$個點裏,方案數共有$\sigma_{x=1}^{k}f[v][x]$種 然後$u$本身有$f[u][j]$種方案 根據乘法原理,把所有方案數乘起來,加到$f[u][j+k]$裏 註意在合並完一個孩子之前要把開輔助數組記錄答案然後再賦值到$f$數組裏 具體看代碼
#pragma GCC optimize("O2")
#include <cstdio>
#include <cstring>
char buf[10000000], *ptr = buf - 1;
inline int readint(){
    int n = 0;
    char ch = *++ptr;
    while(ch < 0 || ch > 9) ch = *++ptr;
    while(ch <= 9 && ch >= 0){
        n = (n << 1) + (n << 3) + (ch ^ 48);
        ch = *++ptr;
    }
    return n;
}
typedef long long ll;
const int maxn = 1000 + 10, mod = 1000000007;
inline void add(ll &x, ll y){
    x = (x + y) % mod;
}
ll C[maxn][maxn];
struct Edge{
    int to, val, next; // (val = 1) <=> ‘>‘ ; (val = 0) <=> ‘<‘
    Edge(){}
    Edge(int _t, int _v, int _n): to(_t), val(_v), next(_n){}
}e[maxn * 2];
int fir[maxn], cnt;
inline void ins(int u, int v, int w){
    e[++cnt] = Edge(v, w, fir[u]); fir[u] = cnt;
    e[++cnt] = Edge(u, w ^ 1, fir[v]); fir[v] = cnt;
}
int n;
ll sum[maxn][maxn];
ll f[maxn][maxn], tp[maxn];
int siz[maxn];
void dfs(int u, int fa){
    siz[u] = f[u][1] = 1;
    for(int v, i = fir[u]; i; i = e[i].next){
        v = e[i].to;
        if(v == fa) continue;
        dfs(v, u);
        for(int j = siz[u] + siz[v]; j; j--) tp[j] = 0;
        // u > v
        if(e[i].val == 1)
            for(int j = 1; j <= siz[u]; j++)
                for(int k = 1; k <= siz[v]; k++)
                    add(tp[j + k], C[j + k - 1][k] * C[siz[u] + siz[v] - j - k][siz[v] - k] % mod * f[u][j] % mod * sum[v][k]);
        else
            for(int j = 1; j <= siz[u]; j++)
                for(int k = 0; k < siz[v]; k++)
                    add(tp[j + k], C[j + k - 1][k] * C[siz[u] + siz[v] - j - k][siz[v] - k] % mod * f[u][j] % mod * (sum[v][siz[v]] - sum[v][k] + mod));
        siz[u] += siz[v];
        for(int j = 1; j <= siz[u]; j++) f[u][j] = tp[j];        
    }
    sum[u][0] = 0;
    for(int i = 1; i <= siz[u]; i++){
        sum[u][i] = sum[u][i - 1] + f[u][i];
        if(sum[u][i] >= mod) sum[u][i] -= mod;
    }
}
void init(){
    n = readint();
    cnt = 0;
    for(int i = 0; i < n; i++) fir[i] = 0;
    int u, v;
    char ch;
    for(int i = 1; i < n; i++){
        u = readint();
        ch = *++ptr;
        while(ch != < && ch != >) ch = *++ptr;
        v = readint();
        if(ch == >) ins(u, v, 1);
        else ins(u, v, 0);
    }
    for(int i = 0; i < n; i++)
        for(int j = 1; j <= n; j++)
            f[i][j] = 0;
}
void init_C(){
    for(int i = 0; i <= 1000; i++) C[i][0] = 1;
    for(int i = 1; i <= 1000; i++)
        for(int j = 1; j <= i; j++){
            C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
            if(C[i][j] >= mod) C[i][j] -= mod;
        }
}
int main(){
    fread(buf, sizeof(char), sizeof(buf), stdin);
    init_C();
    int T = readint();
    while(T--){
        init();
        dfs(0, -1);
        printf("%lld\n", sum[0][n]);
    }
    return 0;
}

[BZOJ3167][Heoi2013]Sao