实际上是给出一个森林,等号的条件用并查集缩起来,把每个森林的根连向0号节点就是一棵树,要给出一个序列使得父亲严格在儿子前面,考虑树形DP,
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示子树
i
i
i中的排列有恰好
j
j
j个小于号的方案数,每次加入一个v的一个子树y形成一个恰好
k
k
k个小于号的排列的转移就是
t
m
p
[
k
]
=
∑
i
=
1
s
i
z
[
v
]
∑
j
=
1
s
i
z
[
y
]
f
[
v
]
[
i
]
∗
f
[
y
]
[
j
]
∗
C
k
i
C
i
j
−
(
k
−
i
)
tmp[k]=\sum_{i=1}^{siz[v]}\sum_{j=1}^{siz[y]}f[v][i]*f[y][j]*C_{k}^iC_{i}^{j-(k-i)}
tmp[k]=∑i=1siz[v]∑j=1siz[y]f[v][i]∗f[y][j]∗CkiCij−(k−i)
其中tmp是一个中间数组,
s
i
z
[
v
]
siz[v]
siz[v]为
v
v
v的已经转移过的儿子的
s
i
z
siz
siz和,且
k
k
k满足
m
a
x
(
i
,
j
)
≤
k
≤
i
+
j
max(i,j)\le k \le i+j
max(i,j)≤k≤i+j
转移的意义是将i个白球,j个黑球放入k个盒子中,同一个盒子中不能有同色球,且每个盒子不为空的方案数,即先选
i
i
i个盒子放白球,剩下的
k
−
i
k-i
k−i个盒子放黑球,现在剩下
j
−
(
k
−
i
)
j-(k-i)
j−(k−i)个黑球,放到
i
i
i个放过白球的盒子中,然后就这样转移就完了
Code:
#include<bits/stdc++.h>
#define mod 1000000007
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=105;
inline int Add(int x,int y){x+=y;if(x>=mod) x-=mod;return x;}
inline void inc(int &x,int y){x+=y;if(x>=mod) x-=mod;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline void Mul(int &x,int y){x=1ll*x*y%mod;}
int vis[N],nxt[N],head[N],tot=0;
inline void add(int x,int y){vis[++tot]=y;nxt[tot]=head[x];head[x]=tot;}
int f[N][N];
int siz[N],C[N][N],tmp[N];
void dp(int v){
int flag=1;
for(int e=head[v];e;e=nxt[e]){
int y=vis[e];dp(y);
if(flag){
flag=0;siz[v]+=siz[y];
for(int i=1;i<=siz[v];i++) f[v][i]=f[y][i];
}
else{
memset(tmp,0,sizeof(tmp));
for(int i=1;i<=siz[v];i++) if(f[v][i])
for(int j=1;j<=siz[y];j++) if(f[y][j])
for(int k=max(i,j);k<=i+j;k++)
inc(tmp[k],mul(mul(f[v][i],f[y][j]),mul(C[k][i],C[i][j-(k-i)])));
siz[v]+=siz[y];
for(int i=1;i<=siz[v];i++) f[v][i]=tmp[i];
}
}
if(flag) f[v][0]=1;++siz[v];
for(int i=siz[v];i;i--) f[v][i]=f[v][i-1];
}
int fa[N],Fa[N],isrt[N];
int get(int x){return fa[x]?fa[x]=get(fa[x]):x;}
int pt[N];
bool check(int v){
if(pt[v]) return false;
pt[v]=1;
for(int i=head[v];i;i=nxt[i]) if(!check(vis[i])) return false;
return true;
}
char ch[5];
int main(){
int n=read(),m=read();
for(int i=0;i<=n;i++){
C[i][0]=1;
for(int j=1;j<=i;j++) C[i][j]=Add(C[i-1][j],C[i-1][j-1]);
}
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%s%d",&x,ch,&y);
if(ch[0]=='='){
int xx=get(x),yy=get(y);
if(xx!=yy) fa[xx]=yy,isrt[xx]=1,Fa[yy]=max(Fa[yy],Fa[xx]);
}
else Fa[y]=x;
}
for(int i=1;i<=n;i++) if(!isrt[i]) add(get(Fa[i]),i);
for(int i=0;i<=n;i++) if(!pt[i]) if(!check(i)) {puts("0");return 0;}
dp(0);
int ans=0;
for(int i=1;i<=siz[0];i++) inc(ans,f[0][i]);
cout<<ans;
return 0;
}