【題解】[CERC2016]二分毯 Bipartite Blanket
阿新 • • 發佈:2022-04-09
前置知識:霍爾定理
對於二分圖,兩部分別為 \(X,Y\),令 \(|X| \le |Y|\),則存在大小為 \(X\) 的匹配的充要條件是對於任意 \(S\subseteq X\),都有 \(|F(S)| \ge |S|\),其中 \(F(S) = \{y\ |\ x\to y \in E,x\in S,y\in Y\}\)。
說人話就是對於 \(X\) 的所有子集,相鄰的點數都不小於子集。
必要性顯然,充分性不顯然,反證一下。
假設滿足條件但是匹配 \(<|X|\),那麼不妨令沒有匹配的點為 \(x\),\(x\) 的所有鄰居都被匹配了,此時從 \(x\) 出發一定存在一條增廣路(匈牙利演算法),如果不存在,則假設這條非增廣路經過 \(X\)
的點集為 \(X'\) ,\(|F(X')|\) 一定 \(<|X'|\),手動畫圖即可理解。
那麼對於本題關鍵結論是
\(V\) 在 \(X\) 中的點集為 \(S\),\(Y\) 中的點集為 \(T\)。如果存在匹配覆蓋 \(S\),並存在匹配覆蓋 \(T\),則一定存在匹配覆蓋 \(V\)。
這結論挺好猜的,\(N\le 20\) 顯然就是折半然後雙指標嘛。證明也不難。
\(S\) 在 \(T\) 中的鄰居為 \(W\),\(S\) 和它的鄰居匹配,然後 \(T/W\) 再進行匹配即可。
所以直接狀壓 DP,\(f_S\) 表示集合 \(S\) 的鄰居集合,\(h_{S}\)
#define N 20 #define M ((1 << N) + 5) int n, m, u[M], v[M], f[M], bt[M], g[M], p[M], q[M], l, r, h[M], a[M], b[M]; char s[N + 1]; int main() { read(n, m); rep(i, 0, n - 1){ scanf("%s", s); rep(j, 0, m - 1)if(s[j] == '1')u[1 << i] |= 1 << j, v[1 << j] |= 1 << i; } rep(i, 0, n - 1)read(p[1 << i]); rep(i, 0, m - 1)read(q[1 << i]); int w = (1 << max(n, m)) - 1; rp(i, w)bt[i] = bt[i >> 1] + (i & 1); w = (1 << n) - 1; h[0] = 1; rp(i, w){ int j = i & -i; p[i] = p[j] + p[i ^ j]; f[i] = u[j] | f[i ^ j]; h[i] = 1; for(int k = i; k; k -= k & -k)h[i] &= h[i ^ (k & -k)]; h[i] &= bt[f[i]] >= bt[i]; if(h[i])a[++l] = p[i]; }a[++l] = 0; w = (1 << m) - 1; rp(i, w){ int j = i & -i; q[i] = q[j] + q[i ^ j]; g[i] = v[j] | g[i ^ j]; h[i] = 1; for(int k = i; k; k -= k & -k)h[i] &= h[i ^ (k & -k)]; h[i] &= bt[g[i]] >= bt[i]; if(h[i])b[++r] = q[i]; }b[++r] = 0; sort(a + 1, a + l + 1), sort(b + 1, b + r + 1); read(w); int j = r; LL ans = 0; rp(i, l){ while(j && b[j] + a[i] >= w)j--; ans += r - j; }printf("%lld\n", ans); return 0; }