Description
Input
Output
Sample Input
5 4
1 < 2
1 < 3
2 < 4
1 = 5
Sample Output
5
Data Constraint
分析:
我们考虑把相同的变成一个点,用并查集处理一下,因为连等只算一次,不需要乘组合数。
因为每个点最多有一个点比这个点优,所以这是一棵树,不过有可能有环,直接输出
0
0
即可。
因为不同子树内的数可以相同,所以我们设为以
x
x
为根的子树,序列被分成了块,每块相等的方案数。
设
f′[x][i]
f
′
[
x
]
[
i
]
是未加入儿子
y
y
的子树的答案,即
这个因为最终有 i i 段,其中自己占了一段,其实能合并的只有 i−1 i − 1 和 j−1 j − 1 段。在 i−1 i − 1 段中选出 j−1 j − 1 放,方案数为 (i−1j−1) ( i − 1 j − 1 ) ;剩下的位置都填第二段的,那么多余的 k−(i−j) k − ( i − j ) 段就要与 j−1 j − 1 段合并,方案数为 (j−1k−(i−j)) ( j − 1 k − ( i − j ) ) 。
那么,总转移式为,
f[x][i]=∑j=1size[x]∑k=1size[x]f′[x][j]∗f[y][k]∗(i−1j−1)∗(j−1k−(i−j))
f
[
x
]
[
i
]
=
∑
j
=
1
s
i
z
e
[
x
]
∑
k
=
1
s
i
z
e
[
x
]
f
′
[
x
]
[
j
]
∗
f
[
y
]
[
k
]
∗
(
i
−
1
j
−
1
)
∗
(
j
−
1
k
−
(
i
−
j
)
)
代码:
// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>
#include <cmath>
#define LL long long
const int maxn=207;
const LL mod=1e9+7;
using namespace std;
int n,m,cnt,num,k,X,Y,s,flag;
int x[maxn],y[maxn],ls[maxn],p[maxn],d[maxn],ru[maxn],size[maxn];
LL f[maxn][maxn],dp[maxn],C[maxn][maxn],ans;
char ch;
struct edge{
int y,next;
}g[maxn];
void add(int x,int y)
{
g[++num]=(edge){y,ls[x]};
ls[x]=num;
}
int find(int x)
{
if (!p[x]) return x;
int y=find(p[x]);
return p[x]=y;
}
void uni(int x,int y)
{
int u=find(x),v=find(y);
if (u==v) return;
p[u]=v;
}
LL binom(int n,int m)
{
if ((n<0) || (m<0) || (m>n)) return 0;
return C[n][m];
}
void dfs(int x,int fa)
{
size[x]=f[x][1]=1;
for (int c=ls[x];c>0;c=g[c].next)
{
int y=g[c].y;
if (y==fa) continue;
if (size[y]) flag=1;
dfs(y,x);
size[x]+=size[y];
for (int i=1;i<=size[x];i++) dp[i]=0;
for (int i=1;i<=size[x];i++)
{
for (int j=1;j<=size[x];j++)
{
for (int k=1;k<=size[x];k++)
{
dp[i]=(dp[i]+f[x][j]*f[y][k]%mod*binom(i-1,j-1)%mod*binom(j-1,k-i+j)%mod)%mod;
}
}
}
for (int i=1;i<=size[x];i++) f[x][i]=dp[i];
}
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
{
scanf("%d",&X);
scanf("%c",&ch);
scanf("%c",&ch);
scanf("%d",&Y);
if (ch=='=') uni(X,Y);
else
{
x[++cnt]=X;
y[cnt]=Y;
}
}
for (int i=1;i<=n;i++)
{
if (find(i)==i) d[i]=++s;
}
for (int i=1;i<=cnt;i++)
{
if (find(x[i])==find(y[i]))
{
printf("0");
return 0;
}
add(d[find(x[i])],d[find(y[i])]);
ru[d[find(y[i])]]++;
}
flag=1;
for (int i=1;i<=s;i++)
{
if (!ru[i]) add(s+1,i),flag=0;
}
C[0][0]=1;
for (int i=1;i<200;i++)
{
C[i][0]=1;
for (int j=1;j<=i;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
}
dfs(s+1,0);
for (int i=1;i<=s+1;i++) ans=(ans+f[s+1][i])%mod;
if (flag) printf("0");
else printf("%lld",ans);
}