数学 Trick 之:断边+子集反演

能够解决的问题

上限制跟有关的某些问题。

优缺点

优点:思路巧妙,题目有区分度。
缺点:无(有点难理解应该不算吧)。

思路

既然跟边有关,那就对边下手,考虑断开一些边(或者说让这些边一定不具有性质,其他的可以不具有性质),分别求答案,然后子集反演回去。

这个过程可以用 树形 \(\text{dp}\) 实现。

就这么抽象,可以先食用例题。

例题与代码

AT_arc101_c [ARC101E] Ribbons on Tree

他的限制为必须经过每条边,所以我们考虑:让一些边一定不被经过,其他边可以不被经过,求答案,那么就简单了。

  • 一个连通块的所有边可以不被经过的方案数即为随机匹配就行:

\[\text{g}(x) = \begin{cases} 0, x\, \& \, 1 = 1 \\ \prod_{i = 1}^{\frac{x}{2}} (2i - 1), x\, \& \, 1 = 0 \\ \end{cases} \]

于是转移(\(dp_{u, j}\)\(u\) 的子树,\(u\) 的连通块大小为 \(j\) 这个状态中,除了 \(u\) 的连通块之外的方案数)。

注:这里 \(tmp\) 是转移前 \(dp\) 的备份,因为这里的每个转移相互独立。

\[dp_{u, j} = dp_{u, j} + (-1) \times g(k) \times tmp_{u, j} \times dp_{son, k} \]

这是将 \((u, son)\) 这条边断掉的转移我们需要实时反演(根据子集反演,断了一条边,需要变号)。

\[dp_{u, j + k} = dp_{u, j + k} + tmp_{u, j} \times dp_{son, k} \]

不断边就简单了。

我知道这非常非常难理解,但是确实只能这么说了,盯着式子意会吧 · · ·

代码!

#include <bits/stdc++.h>
using namespace std;

constexpr int maxn = 5005, modd = 1000000007;

int n, sz[maxn], g[maxn], head[maxn], tot, dp[maxn][maxn], tmp[maxn], ans;
struct Edge {
	int to, nxt;
} e[maxn << 1];

void add(int u, int v) {
	e[++tot] = {v, head[u]};
	head[u] = tot;
}

void dfs(int u, int fa) {
	sz[u] = 1;
	dp[u][1] = 1;
	for (int i = head[u], now; i; i = e[i].nxt) {
		if (now == fa) continue;
		dfs(now, u);
		for (int j = 1; j <= sz[u]; j++) tmp[j] = dp[u][j], dp[u][j] = 0;
		for (int j = 1; j <= sz[u]; j++)
			for (int k = 1; k <= sz[now]; k++) {
				(dp[u][j] += modd - 1ll * tmp[j] * dp[now][k] % modd * g[k] % modd) %= modd;
				(dp[u][j + k] += 1ll * tmp[j] * dp[now][k] % modd) %= modd;
			}
		sz[u] += sz[now];
	}
	return ;
}
signed main() {
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	
	cin >> n;
	for (int i = 1, u, v; i < n; i++) {
		cin >> u >> v;
		add(u, v);
		add(v, u);
	}
	
	g[0] = 1;
	for (int i = 2; i <= n; i += 2) {
		g[i] = 1ll * g[i - 2] * (i - 1) % modd;
	}
	
	dfs(1, 0);
	
	for (int i = 1; i <= n; i++) {
		(ans += 1ll * dp[1][i] * g[i] % modd) %= modd;
	}
	
	cout << ans << '\n';
	
	return 0;
}
posted @ 2025-04-28 21:11  porse114514  阅读(21)  评论(0)    收藏  举报