LOJ6094 归乡迷途

归乡迷途

有一张 \(n\) 个节点组成的无向图,点从 \(1\)\(n\) 编号,图中没有重边和自环。我们不知道它的确切形态,但是它满足以下条件:

  • 由任一节点至节点 \(1\) 的最短路径(经过边数最少的路径)存在且唯一;

  • \(\ell_i\) 表示由节点 \(i\) 至节点 \(1\) 的最短路径上边的数目,那么对于所有 \(2 \leq i \leq n\),有 \(\ell_i \geq \ell_{i-1}\) 成立;

  • 节点 \(i\) 的度数给定,为 \(d_i\),并且所有 \(d_i\) 均等于 \(2\)\(3\)

请计算满足条件的不同的图的数目,输出其除以 \(10^9 + 7\) 的余数。两张无向图不同当且仅当存在点对 \((u, v) \ (1 \leq u < v \leq n)\) 使得其中一张图中 \((u, v)\) 间有边而另一张图中没有。

\(3 \leq n \leq 300,2 \leq d_i \leq 3\)

题解

https://jklover.hs-blog.cf/2020/07/18/Loj-6094-归乡迷途/#more

bfs 树 + dp 计数问题.

限制可以简单归纳为,图的 bfs 树中,每个点的父亲编号小于自己,且非树边只在同一深度的点间出现.

对 bfs 树进行 dp, 每一层加入的数都一定是编号连续的一段,并且只需要记录上一层的信息就可以转移.

\(f(i,j)\) 表示考虑了前 \(i\) 个点,最深的一层有 \(j\) 个点,前 \(i-j\) 个点度数已经满足限制,最后 \(j\) 个点只考虑向父亲连边.

\(g(i,j,k)\) 表示上一层有 \(j\) 个点度数要求为 \(2\) , \(k\) 个点度数要求为 \(3\) ,这层有 \(i\) 个点时的拼接以及上一层内部连边.

枚举上一层有 \(k\) 个点,有 \(f(i,j)=\sum_{k\le i-j}f(i-j,k)\cdot g(j,c_2,c_3)\) , \(c_2,c_3\) 表示 \(k\) 个点中要求度数为 \(2,3\) 的点,由于它们都各自向父亲连了一条边,实际上还需要连的边数是 \(1,2\) .

考虑如何计算转移系数 \(g(i,j,k)\) .

  • \(i>0​\) 时,考虑该层第一个点的父亲是哪个点,有

    \[g(i,j,k)=j\cdot g(i-1,j-1,k)+k\cdot g(i-1,j+1,k-1) \]

  • \(i=0\) 时,此时需要在上一层内互相连边,使得它们满足度数限制,此时再分 \(j>0\)\(j=0\) 讨论.

    • \(i=0,j>0\) 时,枚举第一个还要连 \(1\) 条边的点连的哪个点,有

      \[g(0,j,k)=(j-1)\cdot g(0,j-2,k)+k\cdot g(0,j,k-1) \]

    • \(i=j=0\) 时, \(k\) 个点都要连 \(2\) 条边,一定是若干个互不相交的,大小 \(>2\) 的环,这里犯不着 \(\exp\) ,暴力预处理即可.

最后答案就是 \(\sum f(n,i)\cdot g(0,c_2,c_3)\) ,时间复杂度 \(O(n^3)\) .

注意根节点没有向父亲连的边,儿子方向上的度数不会 \(-1​\) ,需要特判一下,即先将前两层的 \(f​\) 单独算出来.

CO int N=310;
int d[N],fac[N],ifac[N];
int dp[N],g[N][N][N],f[N][N];

IN int C(int n,int m){
	return mul(fac[n],mul(ifac[m],ifac[n-m]));
}
int main(){
	int n=read<int>();
	for(int i=1;i<=n;++i) read(d[i]);
	fac[0]=1;
	for(int i=1;i<=n;++i) fac[i]=mul(fac[i-1],i);
	ifac[n]=fpow(fac[n],mod-2);
	for(int i=n-1;i>=0;--i) ifac[i]=mul(ifac[i+1],i+1);
	dp[0]=1;
	for(int i=3;i<=n;++i)for(int j=3;j<=i;++j)
		inc(dp[i],mul(dp[i-j],mul(C(i-1,j-1),mul(fac[j-1],i2))));
	for(int i=0;i<=n;++i)
		for(int j=0;i+j<=n;++j)for(int k=0;i+j+k<=n;++k){
			if(i==0){
				if(j==0) g[i][j][k]=dp[k];
				else{
					if(j>=2) inc(g[i][j][k],mul(j-1,g[i][j-2][k]));
					if(k>=1) inc(g[i][j][k],mul(k,g[i][j][k-1]));
				}
			}
			else{
				if(j>=1) inc(g[i][j][k],mul(j,g[i-1][j-1][k]));
				if(k>=1) inc(g[i][j][k],mul(k,g[i-1][j+1][k-1]));
			}
		}
	f[1+d[1]][d[1]]=1;
	for(int i=d[1]+2;i<=n;++i)for(int j=1;j<=i-(1+d[1]);++j){
		int c2=0,c3=0;
		for(int k=1;j+k<=i-1;++k){
			d[i-j-k+1]==2?++c2:++c3;
			inc(f[i][j],mul(f[i-j][k],g[j][c2][c3]));
		}
	}
	int ans=0,c2=0,c3=0;
	for(int i=1;i<=n-1;++i){
		d[n-i+1]==2?++c2:++c3;
		inc(ans,mul(f[n][i],g[0][c2][c3]));
	}
	printf("%d\n",ans);
	return 0;
}

posted on 2020-07-20 21:12  autoint  阅读(96)  评论(0编辑  收藏

导航