[THUWC2017] 随机二分图
[题目链接]
[题解]
首先考虑所有边满足 \(t = 0\) 的情况。
不妨设 \(dp_{s1 , s2}\) 表示左侧未选集合为 \(s1\) , 右侧为 \(s2\) 的完美匹配数期望。
根据期望的线性性 , 有 \(dp_{s1 , s2} = \sum_{i \in s1}\sum_{j \in s2}{p_{i , j} \cdot dp_{s1 \oplus bit_{i} , s2 \oplus bit_{j}}}\)。
直接这样计算会将本质相同的一组完美匹配贡献多次 , 因此转移时可以考虑强制去掉最高位 / 最低位。
接着考虑存在 \(t \neq 0\) 的情况。
假设 \(t = 1\) , 不妨将 \((u , v)\) 和 \((a , b)\) 这两条边当作 "\(0\) 类边" 处理 , 将其概率均设为 \(\frac{1}{2}\)。这样在计算答案时 , \((u , v)\) , \((a , b)\) 二者出现一条的概率为 \(\frac{1}{2}\) , 符合要求 , 但 \((u , v)\) , \((a , b)\) 二者同时出现的概率变为了 \(\frac{1}{4}\) , 与要求的 \(\frac{1}{2}\) 不符。 因此不妨加入一条 "四元边" \((u , v , a , b)\) , 其出现概率为 \(\frac{1}{4}\)。 对于 \(t = 2\) 的情况则加入一条概率为 \(-\frac{1}{4}\) 的边。虽然这样不符合常理 , 但根据期望的线性性质是可行的 。
注意当 \((u , v)\) , \((a , b)\) 存在公共点时二者不可兼得 , 故不需要加入 "四元边"。
状态数很大 , 数组存不下 , 可以用一个 \(unordered\)_\(map\) 存储。
时间复杂度 : \(O(?)\)
[代码]
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i , l , r) for (int i = (l); i < (r); ++i)
const int MN = 5005;
const int mod = 1e9 + 7 , inv2 = 500000004, inv4 = 250000002;
unordered_map < int , int > dp , f;
int w[MN] , e[MN] , N , M , tot;
inline void inc(int &x , int y) {
x = x + y < mod ? x + y : x + y - mod;
}
inline int dfs(int s) {
if (!s) return 1;
if (f[s]) return dp[s];
int res = 0;
f[s] = 1;
for (int i = 1; i <= tot; ++i)
if ((e[i] & s) == e[i] && e[i] > s / 2)
inc(res , 1ll * w[i] * dfs(s ^ e[i]) % mod);
return dp[s] = res;
}
int main() {
scanf("%d%d" , &N , &M);
for (int i = 1; i <= M; ++i) {
int op , u , v , a , b;
scanf("%d%d%d" , &op , &u , &v);
--u , --v;
e[++tot] = (1 << u) | (1 << v + N); w[tot] = inv2;
if (!op) continue;
scanf("%d%d" , &a , &b);
--a , --b;
e[++tot] = (1 << a) | (1 << b + N); w[tot] = inv2;
if (e[tot] & e[tot - 1]) continue;
e[tot + 1] = e[tot] | e[tot - 1];
w[++tot] = (op == 1 ? inv4 : mod - inv4);
}
printf("%d\n" , 1ll * (1 << N) * dfs((1 << (2 * N)) - 1) % mod);
return 0;
}