CF848D Shake It!

CF848D Shake It!

给定 \(n,m\),现在按照此规则生成无向图,初始我们有一张图 \(G\),仅包含两个节点 \(s,t\),以及连接 \(s\to t\) 的边。

每次你可以选择一条已经存在的边 \((u,v)\),然后将往图中加入节点 \(w\) 和边 \((u,w),(w,v)\),这样操作 \(n\) 次,我们将得到一张图 \(G'\)

定义 \(G'\) 合法,当且仅当 \(\min cut(s,t)=m\),即 \(s\to t\) 的最小割为 \(m\)

求本质不同的合法的图 \(G'\) 的数量,答案对 \(10^9+7\) 取模。

其中,两张图 \(G_1,G_2\) 不同,当且仅当不存在一种作用于点集的置换,使得边对应相同,同时 \(s,t\) 对应相同。

\(n,m\le 50\)

translated by EmptySoulist

Solution

方便起见,我们认为一次给 \((u,v)\) 加入 \(w\) 的操作为 "加点/添加节点" 操作,我们使用 \((u\to w\to v)\) 来描述此操作。

同时,不难通过观察发现加点有且仅有两种方向(Left and Right)。

请注意,此图上允许对一条边重复添加节点,这非常重要。

我们不难观察到这张图一定是平面图,平面图最小割等于对偶图最短路。

如果不考虑给一条边重复添加节点的情况,我们发现增加节点的过程在对偶图上非常类似于树的形态,考虑一棵树,儿子有 \(0,1\) 两种颜色( \(0\) 表示从左边加,\(1\) 表示右边加)每次增加节点的时候我们给其赋予一个颜色即可。

不难发现此时对偶图最短路即这棵树深度最小的儿子的深度。

接着我们再考虑,允许重复添加节点的情况,我们假设 \((u\to v)\) 的边被加入了两次 \((u\to w_1\to v,u\to w_2\to v)\),同时 \(u\to w_1\) 等边也被加入过点。

我们发现这张平面图上这些边的 内外 顺序是可以任意调控的,这间接使得我们想到,答案应该是只考虑 \(u\to w_1\to v\) 的边存在的情况和 \(u\to w_2\to v\) 存在的情况下答案的和。

通过简单的画图也可以说明这件事。下面将给出一个例子:

第二张图对应的对偶图形如如此:

(保留了 \(s\to t\) 的边方便观看)

其中 \(A\to G\) 的最短路即为答案。

进一步简化,两张图对应的对偶图分别为:

第二张图删去了与 \(G\) 的连边。

注意到这两张图本质上是相同的,也出于进一步的观察,我们不难发现我们可以对真实的对偶图进行一步简化,在初始建图中,假设某条边被操作了 \(k\) 次(且方向相同)我们可以类似于没有边被重复操作时的例子,直接建成树的形态,将这 \(k\) 条边同时挂在 \(u\to v\) 这条边对应的点之下,假设这些边的方向均为 Left,我们发现答案即为这些独立树的答案和!

证明的话画一下图就知道了(具体论证有点麻烦,我不太方便画图 TAT)。

假设 Left 为颜色 \(0\),Right 为颜色 \(1\),那么我们不难得到对一棵简化的树计算答案的方法:

\[f_x=\min(\sum_{x\to v,v\in \textrm{left}} f_v,\sum_{x\to v,v\in \textrm{right}} f_v)+1 \]

由于初始根没有方向区分,所以我们只能将这张图建成森林,其贡献即为各棵子树根节点的 \(f\) 之和 \(+1\)

我们发现本质不同的图,等价于这样简化后的树不同。

那么考虑对树进行计数,我们设 \(g_{i,j}\) 表示 \(i\) 个节点的树,其根节点 \(f\) 值为 \(j\) 的树的方案数。

我们发现本质不同其实说明儿子任意交换对答案没有影响,那么这里类似于无排列规则的计数问题。比如两棵树形如 \(1,2,2\),那么 \(212,122,221\) 均被视为相同的排列。

于是我们对 left 和 right 分别进行转移,然后通过一次类似于卷积的形式合并答案即可。

其中,left 和 right 在转移的过程使用的数组相同,我们发现问题的核心点在于如何去重上了,我们使用 \(f\) 数组来表示我们需要的答案。

假设从小到大加入元素,此时 \(i\) 是我们最后加入的元素,对于 \(i,j\) 不同的元素,我们从小到大枚举 \(j\),这样我们保证了 \((i,j)\) 的对子是按照 \(i\) 为第一关键字,\(j\) 为第二关键字从小到大加入集合的。

对于 \((i,j)\) 相同的对子,我们发现问题等价于有 \(g_{i,j}\) 个数,每个数出现次数任意,如果所有数出现次数相同那么算同一种方案,求方案数。

假设 \(g_{i,j}\) 被使用了 \(k\) 次,那么不难发现贡献即 \(\binom{g_{i,j}+k-1}{k}\),即 \(\frac{1}{(1-x)^k}[x^{g_{i,j}}]\),是经典模型,这样的话我们需要枚举 \(k\)

每次转移得到 \(f\) 之后,我们不难转移 \(g\)

\(g_{i,j}\leftarrow \sum_{u+v=i-1,\min(l,r)=j-1}f_{u,l}f_{v,r}\)

这样我们一边递推 \(g\),一遍递推 \(f\) 即可。

边界为 \(g_{1,1}=1\),同时不难发现我们需要的答案即为 \(f_{n,m-1}\)

复杂度为 \(\mathcal O(n^4\ln n)\)

枚举顺序上有一些坑,建议多想想后写。

\(Code:\)

#include<bits/stdc++.h>
using namespace std ;
#define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
#define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )
#define re register
#define int long long
int gi() {
	char cc = getchar() ; int cn = 0, flus = 1 ;
	while( cc < '0' || cc > '9' ) {  if( cc == '-' ) flus = - flus ; cc = getchar() ; }
	while( cc >= '0' && cc <= '9' )  cn = cn * 10 + cc - '0', cc = getchar() ;
	return cn * flus ;
}
const int P = 1e9 + 7 ; 
const int N = 50 + 5 ; 
int n, m, g[N][N], f[N][N], fac[N], inv[N], D[N][N][N] ;
int fpow(int x, int k) {
	int ans = 1, base = x ;
	while(k) {
		if(k & 1) ans = ans * base % P ;
		base = base * base % P, k >>= 1 ;
	} return ans ;
}
void inc(int &x, int y) {
	((x += y) >= P) && (x -= P) ; 
}
int C(int x, int y) {
	int ans = 1 ;
	rep( i, 1, y ) ans = ans * (x - i + 1) % P ; 
	return ans * inv[y] % P ; 
}
signed main()
{
	n = gi(), m = gi() ; fac[0] = inv[0] = 1 ; 
	rep( i, 1, n ) fac[i] = fac[i - 1] * i % P, inv[i] = fpow( fac[i], P - 2 ) ; 
	g[0][0] = f[0][0] = 1 ; 
	for(re int i = 1; i <= n; ++ i) {
		for(re int u = 0; u < i; ++ u) { 
			int v = i - u - 1 ; 
			rep( l, 0, u ) rep( r, 0, v )
				inc( g[i][min(l, r) + 1], f[u][l] * f[v][r] % P ) ; 
		}
		rep( k, 1, n / i ) rep( j, 1, i ) D[k][i][j] = C(g[i][j] + k - 1, k) ; 
		rep( j, 1, i ) drep( x, i, n ) rep( k, 1, x / i )  {
			int d = D[k][i][j] ; 
			rep( li, k * j, x ) inc( f[x][li], f[x - i * k][li - k * j] * d % P ) ;
		}
	}
	cout << f[n][m - 1] << endl ; 
	return 0 ;
}
posted @ 2020-09-28 22:27  Soulist  阅读(170)  评论(0)    收藏  举报