Bzoj 4824: [Cqoi2017]老C的键盘

来源:互联网 发布:海关出口数据怎么查询 编辑:程序博客网 时间:2024/06/08 15:16

题意简述:给出一个大小为n的完全二叉树,每条边上有一个符号,表示相邻两节点数的大小关系,把一个n的排列填进去,问合法方案数。
题解:用f[i][j]表示第i个节点,排名为j的方案数。对于每个点,把它的子树一棵一棵合并上来,设一棵子树A排名为i,另一棵子树Bj个元素插到i的前面,合法的B的排名是一个连续的区间,能用前缀和优化,j个数插到i前面,size[B]个数插到i后面,要乘两个组合数。

#include<bits/stdc++.h>typedef long long ll;const int N = 105;const int P = 1e9 + 7;struct edge{    int y,next;};edge mp[N];int n,first[N],size[N],s;ll c[N][N],f[N][N],g[N][N],temp[N];char ch[N];void ins(int x, int y){    mp[++s] = (edge) {y,first[x]};    first[x] = s;}void dfs(int cur){    if (cur*2<=n) ins(cur,cur*2);    if (cur*2+1<=n) ins(cur,cur*2+1);    f[cur][1] = g[cur][1] = size[cur] = 1;    for (int t=first[cur]; t>0; t=mp[t].next){        int now = mp[t].y;        dfs(now);        for (int i=1; i<=size[cur]+size[now]; i++) temp[i] = 0;        for (int i=1; i<=size[cur]; i++)            for (int j=0; j<=size[now]; j++)                if (ch[now] == '>')                    temp[i+j] += f[cur][i] * g[now][j] % P * c[i-1+j][i-1] % P                                 * c[size[cur]-i+size[now]-j][size[cur]-i] % P;                else                    temp[i+j] += f[cur][i] * (g[now][size[now]] - g[now][j] + P) % P                                 * c[i-1+j][i-1] % P * c[size[cur]-i+size[now]-j][size[cur]-i] % P;        for (int i=1; i<=size[cur]+size[now]; i++)            f[cur][i] = temp[i] % P, g[cur][i] = (g[cur][i - 1] + f[cur][i]) % P;        size[cur] += size[now];    }}int main(){    //freopen("keyboard.in","r",stdin);    //freopen("keyboard.out","w",stdout);    scanf("%d%s",&n,ch+2);    for (int i=0; i<=n; i++)        for (int j=0; j<=n; j++)            if (j == 0 || j == i)                c[i][j] = 1;            else                c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % P;    dfs(1);    printf("%lld\n",g[1][size[1]]);    return 0;}
0 1
原创粉丝点击