鏈接
題解
用表示以爲根的子樹,分成段的方案數
狀態解釋:段,每一段內部都是等號連接的,段與段之間是小於號連接的
做樹形,合併的時候,假設用和去合併得到
對的貢獻分兩步計算:
先從中選擇段出來,再從中選段出來,然後再把這段和段合併起來,形成段
合併的時候,必須是來自不同子樹的纔可以合併成同一塊
假設把個來自第一棵子樹的塊和個來自第二課子樹的塊合併成個塊,第一塊必須是來自第一棵子樹中的第一塊,而且每個塊不能爲空,每個塊不能包含來自同一棵子樹的兩塊。滿足上述條件的方案數記作
那麼這個寫出來就是
任何兩個點只在處進行一次(樹爲一條鏈的時候取到,否則更小)的合併,所以最終複雜度是
代碼
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define eps 1e-8
#define maxn 110
#define maxe 210
#define cl(x) memset(x,0,sizeof(x))
#define rep(i,a,b) for(i=a;i<=b;i++)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define de(x) cerr<<#x<<" = "<<x<<endl
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll read(ll x=0)
{
ll c, f(1);
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
for(;isdigit(c);c=getchar())x=x*10+c-0x30;
return f*x;
}
struct Graph
{
int etot, head[maxn], to[maxe], next[maxe], w[maxe];
void clear(int N)
{
for(int i=1;i<=N;i++)head[i]=0;
etot=0;
}
void adde(int a, int b, int c=0){to[++etot]=b;w[etot]=c;next[etot]=head[a];head[a]=etot;}
#define forp(pos,G) for(auto p=G.head[pos];p;p=G.next[p])
}G;
struct UnionFind
{
ll f[maxn], size[maxn];
void init(ll n)
{
for(auto i=1;i<=n;i++)f[i]=i, size[i]=1;
}
ll find(ll x){return f[x]==x?x:f[x]=find(f[x]);}
void merge(ll x, ll y)
{
auto fx=find(x), fy=find(y);
f[fx]=fy;
if(fx!=fy)size[fy]+=size[fx];
}
}uf, uf2;
#define mod 1'000'000'007
ll n, dp[maxn][maxn], fa[maxn], indeg[maxn], sz[maxn], m, tmp[maxn], f[maxn][maxn][maxn];
vector< tuple<ll,char,ll> > lis;
void merge(ll u, ll v)
{
ll i, j, k, mx=sz[u]+sz[v];
rep(k,1,mx)tmp[k]=0;
rep(k,1,mx)
{
rep(i,1,sz[u])rep(j,1,sz[v])(tmp[k]+=dp[u][i]*dp[v][j]%mod*f[i][j][k])%=mod;
}
rep(k,1,mx)dp[u][k]=tmp[k];
}
void dfs(ll pos)
{
dp[pos][1]=1;
sz[pos]=1;
forp(pos,G)
{
auto to=G.to[p];
dfs(to);
merge(pos,to);
sz[pos]+=sz[to];
}
}
int main()
{
ll i, j, k;
n=read(), m=read();
uf.init(n);
uf2.init(n+1);
rep(i,1,m)
{
ll f, u; char s[maxn];
scanf("%lld%s%lld",&f,s,&u);
lis.emb( make_tuple(f,*s,u) );
}
for(auto tp:lis)
{
ll f=get<0>(tp), c=get<1>(tp), u=get<2>(tp);
if(c=='=')uf.merge(u,f);
}
for(auto tp:lis)
{
ll f=get<0>(tp), c=get<1>(tp), u=get<2>(tp);
if(c=='<')
{
fa[uf.find(u)]=uf.find(f);
indeg[uf.find(f)]++;
}
}
rep(i,1,n)if(uf.find(i)==i and fa[i]==0)
{
fa[i]=n+1;
indeg[n+1]++;
}
rep(i,1,n)if(uf.find(i)==i)
{
G.adde(fa[i],i);
if(uf2.find(fa[i])!=uf2.find(i))
{
uf2.merge(fa[i],i);
}
else
{
printf("0");
return 0;
}
}
f[1][0][1]=1;
for(k=2;k<=n+1;k++)rep(i,0,n+1)rep(j,0,n+1)
{
if(i)f[i][j][k]+=f[i-1][j][k-1];
if(j)f[i][j][k]+=f[i][j-1][k-1];
if(i and j)f[i][j][k]+=f[i-1][j-1][k-1];
f[i][j][k]%=mod;
}
dfs(n+1);
ll ans=0;
rep(i,1,n+1)(ans+=dp[n+1][i])%=mod;
printf("%lld",ans);
return 0;
}