传送门
题意:
有一张图,其中1号点是首都。已知编号更小的点到首都的最短距离一定不会超过编号更大的点。(距离定义为经过的边数) 要求每个点到首都的最短路径唯一。 且图上不存在重边与自环。 给定所有点的度数(2或3),求方案数mod 10^9+7。 n<=50
思路:
看到限制就应该有大概思路:一个合法的图应该是分层的,且每一层中的数编号连续。
于是不难设置状态
f
i
,
j
f_{i,j}
fi,j表示前
i
i
i个点最后一层有
j
j
j个点的方案数。
考虑枚举上一层的节点数
k
k
k转移:
f
i
,
j
=
f
i
−
j
,
k
∗
?
?
?
f_{i,j}=f_{i-j,k}*???
fi,j=fi−j,k∗???
于是将问题转化成了求
?
?
?
???
???
这个
?
?
?
???
???可以
d
p
dp
dp出来。
定义状态
g
i
,
j
,
k
g_{i,j,k}
gi,j,k表示当前层有
i
i
i个点,上一层有
j
j
j个度数为
2
2
2的和
k
k
k个度数为
1
1
1的,且当前层每个点恰和上一层某个点相连的方案数。
这个
?
?
?
???
???就等于
g
j
,
c
n
t
_
d
u
_
2
i
−
j
−
k
+
1
,
i
−
j
,
c
n
t
_
d
u
_
3
i
−
j
−
k
+
1
,
i
−
j
g_{j,cnt\_du\_2_{i-j-k+1,i-j},cnt\_du\_3_{i-j-k+1,i-j}}
gj,cnt_du_2i−j−k+1,i−j,cnt_du_3i−j−k+1,i−j
至于
g
g
g的预处理可以分情况讨论。
详见代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
const int mod=1e9+7;
typedef long long ll;
inline int add(const int&a,const int&b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(const int&a,const int&b){return a>=b?a-b:a-b+mod;}
inline int mul(const int&a,const int&b){return (ll)a*b%mod;}
inline void Add(int&a,const int&b){a=a+b>=mod?a+b-mod:a+b;}
inline void Dec(int&a,const int&b){a=a>=b?a-b:a-b+mod;}
inline void Mul(int&a,const int&b){a=(ll)a*b%mod;}
const int N=55;
int n,a[N],f[N][N],g[N][N][N],c1[N][N],c2[N][N],C[N][N],coe[N],ans=0;
inline void init(){
for(ri i=0;i<=n;++i){
C[i][0]=1;
for(ri j=1;j<=i;++j)C[i][j]=add(C[i-1][j],C[i-1][j-1]);
}
coe[3]=1;
for(ri i=4;i<=n;++i)coe[i]=mul(coe[i-1],i-1);
}
int main(){
n=read();
init();
for(ri i=1;i<=n;++i)a[i]=read();
for(ri l=1;l<=n;++l)for(ri r=l;r<=n;++r){
c1[l][r]=c1[l][r-1]+(a[r]==2);
c2[l][r]=c2[l][r-1]+(a[r]==3);
}
g[0][0][0]=1;
for(ri i=3;i<=n;++i)for(ri j=3;j<=i;++j)Add(g[0][0][i],mul(coe[j],mul(C[i-1][j-1],g[0][0][i-j])));
for(ri i=1;i<=n;++i)for(ri j=0;j<=n;++j)g[0][i][j]=add(i>=2?mul(i-1,g[0][i-2][j]):0,j?mul(j,g[0][i][j-1]):0);
for(ri i=1;i<=n;++i)for(ri j=0;j<=n;++j)for(ri k=0;k<=n;++k)g[i][j][k]=add(j?mul(j,g[i-1][j-1][k]):0,k?mul(k,g[i-1][j+1][k-1]):0);
f[a[1]+1][a[1]]=1;
for(ri i=a[1]+2;i<=n;++i)for(ri j=1;j+a[1]+1<=i;++j)for(ri k=1;k<=i-j;++k)
Add(f[i][j],mul(f[i-j][k],g[j][c1[i-j-k+1][i-j]][c2[i-j-k+1][i-j]]));
for(ri i=1;i<=n;++i)Add(ans,mul(f[n][i],g[0][c1[n-i+1][n]][c2[n-i+1][n]]));
cout<<ans;
return 0;
}