P4547 [THUWC2017]随机二分图(状压,期望DP)

Posted jiazp

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4547 [THUWC2017]随机二分图(状压,期望DP)相关的知识,希望对你有一定的参考价值。

期望好题。

发现 (n) 非常小,应该要想到状压的。

我们可以先只考虑 0 操作。

最难的还是状态:

我们用 (S) 表示左部点有哪些点已经有对应点, (T) 表示右部点有哪些点已经有对应点,(f[S][T]) 表示从一条边没连到此状态的期望方案数

这样就有转移:

[f[S][T] <- sum_{s in S,t in T}f[S oplus s][T oplus t] * p(s, t) ]

也就是说,从没选的点中选俩点连边。不过这可能会算重(先连 (e_1) 后连 (e_2) 和先连 (e_2) 后连 (e_1) 都会计入答案)。因此我们强制要求选择 (S) 中编号最小的点连边,这样每种答案就只被计算一次了。

然后考虑 1,2 操作。1,2 操作并没有改变两条边各自出现的概率,只是改变的两条边同时出现的概率。因此我们可以加一些特殊的边 (e_1, e_2) ,并要求 (e_1, e_2) 必须一起被选,这样就可以调节同时出现的概率。具体来说就是 1 操作加 (frac{1}{4}),2操作减 (frac{1}{4})

然后就没啥难点了。考虑到合法状态数不多,直接记忆化搜索即可。

const int P = 1e9 + 7;
inline ll quickpow(ll x, int k) {
	ll res = 1;
	while (k) {
		if (k & 1)	res = res * x % P;
		x = x * x % P;
		k >>= 1;
	}
	return res;
}
int inv2, inv4;
int n, m;
struct edge {
	int s, t, p;
}e[N];
int ecnt;

map<int, ll> mp[NN];
inline ll dfs(int S, int T) {
	if (S == 0 && T == 0)	return 1;
	if (mp[S].count(T))	return mp[S][T];
	ll res = 0;
	for (register int i = 1; i <= ecnt; ++i) {
		int s = e[i].s, t = e[i].t, p = e[i].p;
		if (((S | s) != S) || ((T | t) != T))	continue;
		if ((s | (lowbit(S))) != s)	continue;
		res = (res + dfs(S ^ s, T ^ t) * p) % P;
	}
	mp[S][T] = res;
	return res;
}

int main() {
	inv2 = quickpow(2, P - 2);
	inv4 = quickpow(4, P - 2);
	read(n), read(m);
	for (register int i = 1; i <= m; ++i) {
		int t, x, y; read(t), read(x), read(y);
		--x, --y;
		e[++ecnt] = (edge){1 << x, 1 << y, inv2};
		if (t) {
			int a, b; read(a), read(b);
			--a, --b;
			e[++ecnt] = (edge){(1 << a), (1 << b), inv2};//Attention!
			if (a == x || b == y)	continue;
			e[++ecnt] = (edge){(1 << x) | (1 << a), (1 << y) | (1 << b), t == 1 ? inv4 : P - inv4};
		}
	}
	ll ans = dfs((1 << n) - 1, (1 << n) - 1) * (1 << n) % P;
	printf("%lld
", ans);
	return 0;
}

以上是关于P4547 [THUWC2017]随机二分图(状压,期望DP)的主要内容,如果未能解决你的问题,请参考以下文章

「THUWC 2017」随机二分图

[THUWC2017]随机二分图

[THUWC2017]随机二分图

「CSP-S模拟赛」2019第二场

THUWC2018 随机算法

CodeforcesGym 101173B Bipartite Blanket 霍尔定理+状压DP