[题目链接]
[题解]
首先考虑所有边满足 (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 eq 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
" , 1ll * (1 << N) * dfs((1 << (2 * N)) - 1) % mod);
return 0;
}