[BZOJ3167][Heoi2013]Sao
Posted Elder_Giang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ3167][Heoi2013]Sao相关的知识,希望对你有一定的参考价值。
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
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
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的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ3167/4824[Heoi2013]Sao/[Cqoi2017]老C的键盘