BZOJ 3996 [TJOI 2015] 线性代数 解题报告
首先,我们可以得到:
$$D = \sum_{i=1}^{n}\sum_{j=1}^{n}a_i\times a_j\times b_{i,j} - \sum_{i=1}^{n}a_i\times c_i$$
那么是不是就相当于这样的问题:
有 $n$ 个物品,你可以选择一些物品出来,如果同时选了 $i,j$ 两个物品那么就有 $b_{i,j}$ 的收益,然而每一个物品都有一个代价 $c_i$,求最大收益。
这是经典的最小割模型:
- 连边 $S\to Dot(i,j)$,流量为 $b_{i,j}$。
- 连边 $Dot(i,j)\to i$ 以及 $Dot(i,j)\to j$,流量为 $\infty$。
- 连边 $i\to T$,流量为 $c_i$
设最小割为 $x$,那么答案就是:
$$\sum_{i=1}^{n}\sum_{j=1}^{n}b_{i,j} - x$$
尽管有很多个点,但还是可以跑得很快的。(*^_^*)
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 using namespace std; 7 typedef long long LL; 8 #define N 250000 + 500 + 5 9 #define M 2500000 + 5 10 #define INF 0x7fffffff 11 12 int n, S, T, cnt, tot = 1; 13 int Head[N], q[N], Dfn[N]; 14 LL ans; 15 16 struct Edge 17 { 18 int next, node, flow; 19 }h[M]; 20 21 inline void addedge(int u, int v, int fl) 22 { 23 h[++ tot].next = Head[u], Head[u] = tot; 24 h[tot].node = v, h[tot].flow = fl; 25 h[++ tot].next = Head[v], Head[v] = tot; 26 h[tot].node = u, h[tot].flow = 0; 27 } 28 29 inline bool BFS() 30 { 31 for (int i = S; i <= T; i ++) 32 Dfn[i] = 0; 33 int l = 1, r = 1; 34 q[1] = S, Dfn[S] = 1; 35 while (l <= r) 36 { 37 int z = q[l ++]; 38 for (int i = Head[z]; i; i = h[i].next) 39 { 40 int d = h[i].node, p = h[i].flow; 41 if (!p || Dfn[d]) continue ; 42 Dfn[d] = Dfn[z] + 1; 43 q[++ r] = d; 44 if (d == T) return 1; 45 } 46 } 47 return 0; 48 } 49 50 inline int dinic(int z, int inflow) 51 { 52 if (z == T) return inflow; 53 int ret = inflow, flow; 54 for (int i = Head[z]; i; i = h[i].next) 55 { 56 int d = h[i].node, p = h[i].flow; 57 if (Dfn[d] != Dfn[z] + 1 || !p) continue ; 58 flow = dinic(d, min(p, ret)); 59 ret -= flow; 60 h[i].flow -= flow, h[i ^ 1].flow += flow; 61 if (!ret) return inflow; 62 } 63 if (ret == inflow) Dfn[z] = -1; 64 return inflow - ret; 65 } 66 67 int main() 68 { 69 #ifndef ONLINE_JUDGE 70 freopen("3996.in", "r", stdin); 71 freopen("3996.out", "w", stdout); 72 #endif 73 74 scanf("%d", &n); 75 S = 0, T = n + n * n + 1, cnt = n; 76 for (int i = 1; i <= n; i ++) 77 for (int j = 1, w; j <= n; j ++) 78 { 79 scanf("%d", &w); 80 addedge(S, ++ cnt, w); 81 addedge(cnt, i, INF); 82 addedge(cnt, j, INF); 83 ans += w; 84 } 85 for (int i = 1, w; i <= n; i ++) 86 { 87 scanf("%d", &w); 88 addedge(i, T, w); 89 } 90 while (BFS()) 91 ans -= dinic(S, INF); 92 printf("%lld\n", ans); 93 94 #ifndef ONLINE_JUDGE 95 fclose(stdin); 96 fclose(stdout); 97 #endif 98 return 0; 99 }