【费用流】loj#545. 「LibreOJ β Round #7」小埋与游乐场

好像现在看来这个缩点的思路挺清晰啊

题目描述

有两个非负整数组成的可重集合 $A$ 和 $B$。

现在你可以对 $A$ 中至多 $k$ 个元素进行操作。操作方法为:设你准备操作且未被操作过的 $A$ 中的元素是 $a$,你可以在 $B$ 中选取任意一个元素 $b$,将 $a$ 修改为 $aoplus 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)= egin{cases} max({2^k:kin mathbb{N},2^k|x}) & xin 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}$ 之和的可能的最小值。

数据范围

对于所有数据,$1le n,m,kle 1.2 imes 10^6,0le a_i,b_ile 10^9$


题目分析

注意到只有两种类型操作是有效的:

  1. $lowbit(a_i) > lowbit(b_i)$
  2. $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
",ans);
97     return 0;
98 }

END

原文地址:https://www.cnblogs.com/antiquality/p/10473335.html