【费用流】loj#545. 「LibreOJ β Round #7」小埋与游乐场
好像现在看来这个缩点的思路挺清晰啊
题目描述
有两个非负整数组成的可重集合 $A$ 和 $B$。
现在你可以对 $A$ 中至多 $k$ 个元素进行操作。操作方法为:设你准备操作且未被操作过的 $A$ 中的元素是 $a$,你可以在 $B$ 中选取任意一个元素 $b$,将 $a$ 修改为 $a\oplus b$(这里 $\oplus$ 表示二进制按位异或),然后从 $B$ 中删去 $b$。
最终,你要使 $A$ 中所有元素的 $\mathrm{lowbit}$ 之和最小。正整数的 $\mathrm{lowbit}$ 定义为其二进制最低非零位的值,$0$ 的 $\mathrm{lowbit}$ 规定为 $0$,例如 $\mathrm{lowbit}(0)=0,\mathrm{lowbit}(1)=1,\mathrm{lowbit}(24)=8$。形式化地有:
$\mathrm{lowbit}(x)= \begin{cases} \max(\{2^k:k\in \mathbb{N},2^k|x\}) & x\in \mathbb{N}^+\\ 0 & x=0 \end{cases}$
(其中 $|$ 表示整除)
你需要求出操作后 $A$ 中所有元素的 $\mathrm{lowbit}$ 之和的可能的最小值。
输入格式
第一行一个整数 $n$ 表示 $A$ 的元素个数。
接下来一行 $n$ 个整数 $\{a_i\}$ 表示 $A$ 中元素。
接下来一行一个整数 $m$ 表示 $B$ 的元素个数。
接下来一行 $m$ 个整数 $\{b_i\}$ 表示 $B$ 中元素。
接下来一行一个整数 $k$。
输出格式
输出一行一个整数 $S$ 表示操作后 $A$ 中所有元素的 $\mathrm{lowbit}$ 之和的可能的最小值。
数据范围
对于所有数据,$1\le n,m,k\le 1.2\times 10^6,0\le a_i,b_i\le 10^9$
题目分析
注意到只有两种类型操作是有效的:
- $lowbit(a_i) > lowbit(b_i)$
- $a_i=b_i$
那么对于$lowbit$相同的点,实际上可以作为等价类考虑。首先预处理出$cnt_{a/b}$表示${{a/b}_i}$中的具有相同lowbit的数目;$cnt_c$表示$a_i$与$b_i$的具有相同lowbit的交。
连边则是在$a_i$和$b_j(j < i)$间连$(INF,2^{i-1}-2^{j-1})$的边;在$a_i$和$b_i$之间连$(cnt_{ci},2^{i-1})$的边;$S$向$a_i$连$(cnt_{ai},0)$的边;$b_i$向$T'$连$(cnt_{bi},0)$的边;最后$T'$向$T$连$(k,0)$的边限制流量。
由于所求的是最小值,那么对于这张图应该跑最大费用可行流。写的时候没带脑子地直接写了个最大费用最大流。
1 #include<bits/stdc++.h> 2 typedef long long ll; 3 const int maxn = 1200035; 4 const int maxm = 200035; 5 const int maxNode = 2035; 6 const ll INF = 2e9; 7 8 struct Edge 9 { 10 int u,v,f,c,dis; 11 Edge(int a=0, int b=0, int c=0, int d=0, int e=0):u(a),v(b),f(c),c(d),dis(e) {} 12 }edges[maxm]; 13 int n,m,K,S,T,befT; 14 int edgeTot,head[maxNode],nxt[maxm],bck[maxNode],flw[maxNode]; 15 int a[maxn],b[maxn],cnta[35],cntb[35],cntc[35]; 16 bool inq[maxNode]; 17 ll ans,dis[maxNode]; 18 19 int read() 20 { 21 char ch = getchar(); 22 int num = 0, fl = 1; 23 for (; !isdigit(ch); ch=getchar()) 24 if (ch=='-') fl = -1; 25 for (; isdigit(ch); ch=getchar()) 26 num = (num<<1)+(num<<3)+ch-48; 27 return num*fl; 28 } 29 int lowbit(int x) 30 { 31 if (!x) return 0; 32 return log2(x&-x)+1; 33 } 34 void addedge(int u, int v, int c, int dis) 35 { 36 edges[edgeTot] = Edge(u, v, 0, c, dis), nxt[edgeTot] = head[u], head[u] = edgeTot, ++edgeTot; 37 edges[edgeTot] = Edge(v, u, 0, 0, -dis), nxt[edgeTot] = head[v], head[v] = edgeTot, ++edgeTot; 38 } 39 void maxFlow() 40 { 41 for (;;) 42 { 43 std::queue<int> q; 44 memset(flw, 0, sizeof flw); 45 memset(bck, 0, sizeof bck); 46 memset(dis, -0x3f3f3f3f, sizeof dis); 47 q.push(S), flw[S] = INF, dis[S] = 0; 48 for (int tmp; q.size(); ) 49 { 50 tmp = q.front(), q.pop(), inq[tmp] = 0; 51 for (int i=head[tmp]; i!=-1; i=nxt[i]) 52 { 53 int v = edges[i].v; 54 if (dis[tmp]+edges[i].dis > dis[v]&&edges[i].f < edges[i].c){ 55 bck[v] = i, dis[v] = dis[tmp]+edges[i].dis; 56 flw[v] = std::min(flw[tmp], edges[i].c-edges[i].f); 57 if (!inq[v]) inq[v] = 1, q.push(v); 58 } 59 } 60 } 61 if (dis[T] < 0) return; 62 for (int i=T; i!=S; i=edges[bck[i]].u) 63 edges[bck[i]].f += flw[T], edges[bck[i]^1].f -= flw[T]; 64 ans -= dis[T]*flw[T]; 65 } 66 } 67 int main() 68 { 69 memset(head, -1, sizeof head); 70 n = read(); 71 for (int i=1, val; i<=n; i++) 72 a[i] = read(), val = lowbit(a[i]), ++cnta[val], ans += val?(1ll<<(val-1)):0; 73 m = read(); 74 for (int i=1; i<=m; i++) 75 b[i] = read(), ++cntb[lowbit(b[i])]; 76 std::sort(a+1, a+n+1); 77 std::sort(b+1, b+m+1); 78 for (int i=1, j=1, p=1, q=1; i<=n; i=j+1) 79 { 80 for (j = i; j!=n&&a[j]==a[j+1]; ++j); 81 for (; p < m&&b[p] < a[i]; ++p); 82 for (q = p; p <= m&&b[p]==a[i]; ++p); 83 cntc[lowbit(a[i])] += std::min(j-i+1, p-q); 84 } 85 K = read(), S = 32*2+10, T = S+1, befT = T+1; 86 addedge(befT, T, K, 0); 87 for (int i=1; i<=31; i++) 88 { 89 addedge(S, i, cnta[i], 0); 90 addedge(i+32, befT, cntb[i], 0); 91 addedge(i, i+32, cntc[i], 1<<(i-1)); 92 for (int j=1; j<i; j++) 93 addedge(i, j+32, INF, (1<<(i-1))-(1<<(j-1))); 94 } 95 maxFlow(); 96 printf("%lld\n",ans); 97 return 0; 98 }
END