题解:
这题不会做……
一开始以为是拓扑序计数,觉得不太可做,后来仔细看题目才发现只有树的情况(有环则无解),然而还是不会。
难点是如何将两个状态合并。如果只记录方案数的话,是无法将两个状态合并的。所以设计状态时加多一维。
f
i
,
j
f_{i,j}
fi,j表示以
i
i
i为根的子树,分为
j
j
j段的方案数,这里的每一段都是用等于号相连,而段与段之间用小于号相连,这样就可以转移了。具体一点的话就是枚举合并后有多少段,然后再乘个组合数。
注意图有可能是森林,为了方便,可以加一个虚根连向所有的根。
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=110;
const int inf=2147483647;
const int mod=1000000007;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
void upd(int &x,int y){x+=y;if(x>=mod)x-=mod;}
int n,m,f[Maxn][Maxn],g[Maxn],rt[Maxn],fa[Maxn],ex[Maxn],ey[Maxn],from[Maxn],deg[Maxn],sz[Maxn];
int findrt(int x){return((rt[x]==x)?x:rt[x]=findrt(rt[x]));}
struct Edge{int y,next;}e[Maxn<<1];
int last[Maxn],len=0;
void ins(int x,int y)
{
int t=++len;
e[t].y=y;e[t].next=last[x];last[x]=t;
}
int p;bool flag;
void go(int x)
{
if(!x)return;
if(x==p){flag=true;return;}
go(from[findrt(x)]);
}
int C[Maxn][Maxn];
void pre()
{
C[0][0]=1;
for(int i=1;i<=n+1;i++)
{
C[i][0]=1;
for(int j=1;j<=i;j++)
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
}
void dfs(int x)
{
sz[x]=0;
if(!last[x]){sz[x]=f[x][1]=1;return;}
bool fir=true;
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].y;
dfs(y);
if(fir)
{
fir=false;
for(int j=1;j<=sz[y];j++)
f[x][j]=f[y][j];
}
else
{
memset(g,0,sizeof(g));
for(int j=1;j<=sz[x];j++)
if(f[x][j])
{
for(int k=1;k<=sz[y];k++)
if(f[y][k])
{
for(int l=max(j,k);l<=j+k;l++)
upd(g[l],(LL)f[x][j]*f[y][k]%mod*C[l][j]%mod*C[j][k-(l-j)]%mod);
}
}
for(int j=1;j<=sz[x]+sz[y];j++)f[x][j]=g[j];
}
sz[x]+=sz[y];
}
sz[x]++;
for(int i=sz[x];i;i--)f[x][i]=f[x][i-1];
}
int main()
{
memset(f,0,sizeof(f));
n=read(),m=read();pre();
for(int i=1;i<=n;i++)rt[i]=i;
for(int i=1;i<=m;i++)
{
int x,y;char str[3];
x=read();scanf("%s",str);y=read();
if(str[0]=='=')
{
int fx=findrt(x),fy=findrt(y);
if(fx==fy)continue;
rt[fx]=fy;
}
else ex[i]=x,ey[i]=y,from[y]=x;
}
for(int i=1;i<=n;i++)
{
flag=false;p=i;
go(from[findrt(i)]);
if(flag)return puts("0"),0;
}
for(int i=1;i<=m;i++)
if(ex[i])ins(findrt(ex[i]),findrt(ey[i])),deg[findrt(ey[i])]++;
for(int i=1;i<=n;i++)if(findrt(i)==i&&!deg[i])ins(n+1,i);
dfs(n+1);
int ans=0;
for(int i=1;i<=n+1;i++)upd(ans,f[n+1][i]);
printf("%d",ans);
}