题意:
问多少种出栈方式满足所有限制: x i x_i xi在 y i y_i yi前先出栈。
题解:
容易看出,一个合法的括号序列一定对应一棵先序遍历为0~n的树(加个虚根)。
而这些限制就是当
x
i
<
y
i
x_i<y_i
xi<yi,则
y
i
y_i
yi在
x
i
x_i
xi子树外,当
x
i
>
y
i
x_i>y_i
xi>yi,则
y
i
y_i
yi在
x
i
x_i
xi子树内。
所以
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示
i
i
i~
j
j
j这段区间,组成合法森林的方案数。
转移枚举第一棵子树的大小即可。
code:
#include<map>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#define LL long long
#define mp make_pair
using namespace std;
const int mod=1e9+7;
int n,r[310],m,l[310];
map<pair<int,int>,int> f;
int dfs(int x,int k)
{
if(k<x) return 1;
if(f.count(mp(x,k))) return f[mp(x,k)];
int &g=f[mp(x,k)];
for(int i=l[x];i<=min(r[x],k);i++)
(g+=(LL)dfs(x+1,i)*dfs(i+1,k)%mod)%=mod;
return g;
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++) l[i]=i,r[i]=n;
bool flag=false;
for(int i=1;i<=m;i++)
{
int A,B;scanf("%d %d",&A,&B);
if(A==B) flag=true;
if(A<B) r[A]=min(r[A],B-1);
else l[B]=max(l[B],A);
}
if(flag) {puts("0");continue;}
f.clear();
printf("%d\n",dfs(1,n));
}
}