首先可以直接把整个序列建成一个完全二叉树的结构,这个应该都看得出来
然后考虑树形dp,以大于为例
设$f[i][j]$表示$i$这个节点在子树中排名第$j$位时的总方案数(因为实际只与相对大小有关,与实际数值无关)
我们考虑如果从当前子树中弄出$k$个节点,其他子树中弄出$j-1$个节点,那么当前节点的大小排名就是$k+j$
然后考虑一下,如果我们不看这个子树,根节点排在第$j$个,方案数是$f[i][j]$,如果只看此子树,此子树的根就是根节点的儿子,它在此子树中的排名可能是$1,2,...k$,那么我们就需要记录一下前缀和
然后考虑合并排列
对于小于根节点的,选出$j-1$个非此子树,对于大于根节点的,选出$sum[x]-1$个非此子树里弄出来的,那么就是一个组合问题了
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #define ll long long 6 using namespace std; 7 const int N=105,mod=1e9+7; 8 int n,tot;char s[N]; 9 ll f[N][N],g[N][N],tmp[N],c[N][N]; 10 int head[N],ver[N<<1],Next[N<<1],sum[N]; 11 inline void add(int u,int v){ 12 ver[++tot]=v,Next[tot]=head[u],head[u]=tot; 13 } 14 void dfs(int x){ 15 int l=x<<1,r=l|1;; 16 if(l<=n) add(x,l); 17 if(r<=n) add(x,r); 18 g[x][1]=f[x][1]=sum[x]=1; 19 for(int i=head[x];i;i=Next[i]){ 20 int v=ver[i];dfs(v); 21 memset(tmp,0,sizeof(tmp)); 22 for(int j=1;j<=sum[x];++j) 23 for(int k=0;k<=sum[v];++k){ 24 if(s[v]=='>') 25 tmp[j+k]+=f[x][j]*g[v][k]%mod 26 *c[j+k-1][j-1]%mod*c[sum[x]+sum[v]-j-k][sum[x]-j]%mod; 27 else tmp[j+k]+=f[x][j]*(g[v][sum[v]]-g[v][k]+mod)%mod 28 *c[j+k-1][j-1]%mod*c[sum[x]+sum[v]-j-k][sum[x]-j]%mod; 29 } 30 sum[x]+=sum[v]; 31 for(int j=1;j<=sum[x];++j) 32 f[x][j]=tmp[j]%mod,g[x][j]=(g[x][j-1]+f[x][j])%mod; 33 } 34 } 35 int main(){ 36 // freopen("testdata.in","r",stdin); 37 scanf("%d%s",&n,s+2); 38 c[0][0]=1; 39 for(int i=1;i<=n;++i){ 40 c[i][0]=1; 41 for(int j=1;j<=i;++j) 42 c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod; 43 } 44 dfs(1);printf("%lld ",g[1][sum[1]]); 45 return 0; 46 }