#line 1 "main.cpp" #line 1 "main.cpp" /** * @title Template */ #include #include #include #include #include #include #include #include template inline bool chmin(T &lhs, const U &rhs) { if (lhs > rhs) { lhs = rhs; return true; } return false; } template inline bool chmax(T &lhs, const U &rhs) { if (lhs < rhs) { lhs = rhs; return true; } return false; } struct range { using itr = int64_t; struct iterator { itr i; constexpr iterator(itr i_) noexcept : i(i_) { } constexpr void operator ++ () noexcept { ++i; } constexpr itr operator * () const noexcept { return i; } constexpr bool operator != (iterator x) const noexcept { return i != x.i; } }; const iterator l, r; constexpr range(itr l_, itr r_) noexcept : l(l_), r(std::max(l_, r_)) { } constexpr iterator begin() const noexcept { return l; } constexpr iterator end() const noexcept { return r; } }; struct revrange { using itr = int64_t; struct iterator { itr i; constexpr iterator(itr i_) noexcept : i(i_) { } constexpr void operator ++ () noexcept { --i; } constexpr itr operator * () const noexcept { return i; } constexpr bool operator != (iterator x) const noexcept { return i != x.i; } }; const iterator l, r; constexpr revrange(itr l_, itr r_) noexcept : l(l_ - 1), r(std::max(l_, r_) - 1) { } constexpr iterator begin() const noexcept { return r; } constexpr iterator end() const noexcept { return l; } }; #line 2 "/Users/kodamankod/Desktop/Programming/Library/other/fast_io.cpp" #include #include #include #line 7 "/Users/kodamankod/Desktop/Programming/Library/other/fast_io.cpp" namespace fast_io { static constexpr size_t buf_size = 1 << 18; static constexpr size_t buf_margin = 1; static constexpr size_t block_size = 10000; static constexpr size_t integer_size = 20; static char inbuf[buf_size + buf_margin] = {}; static char outbuf[buf_size + buf_margin] = {}; static char block_str[block_size * 4 + buf_margin] = {}; static constexpr uint64_t power10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 100000000000, 1000000000000, 10000000000000, 100000000000000, 1000000000000000, 10000000000000000, 100000000000000000, 1000000000000000000, 10000000000000000000u }; class scanner { private: size_t M_in_pos = 0, M_in_end = buf_size; void M_load() { M_in_end = fread(inbuf, 1, buf_size, stdin); inbuf[M_in_end] = '\0'; } void M_reload() { size_t length = M_in_end - M_in_pos; memmove(inbuf, inbuf + M_in_pos, length); M_in_end = length + fread(inbuf + length, 1, buf_size - length, stdin); inbuf[M_in_end] = '\0'; M_in_pos = 0; } void M_ignore_space() { while (inbuf[M_in_pos] <= ' ') { if (__builtin_expect(++M_in_pos == M_in_end, 0)) M_reload(); } } char M_next() { return inbuf[M_in_pos++]; } char M_next_nonspace() { M_ignore_space(); return inbuf[M_in_pos++]; } public: scanner() { M_load(); } void scan(char &c) { c = M_next_nonspace(); } void scan(std::string &s) { M_ignore_space(); s = ""; do { size_t start = M_in_pos; while (inbuf[M_in_pos] > ' ') ++M_in_pos; s += std::string(inbuf + start, inbuf + M_in_pos); if (inbuf[M_in_pos] != '\0') break; M_reload(); } while (true); } template typename std::enable_if::value, void>::type scan(T &x) { char c = M_next_nonspace(); if (__builtin_expect(M_in_pos + integer_size >= M_in_end, 0)) M_reload(); bool n = false; if (c == '-') n = true, x = 0; else x = c & 15; while ((c = M_next()) >= '0') x = x * 10 + (c & 15); if (n) x = -x; } template void scan(T &x, Args&... args) { scan(x); scan(args...); } template scanner& operator >> (T &x) { scan(x); return *this; } }; class printer { private: size_t M_out_pos = 0; void M_flush() { fwrite(outbuf, 1, M_out_pos, stdout); M_out_pos = 0; } void M_precompute() { for (size_t i = 0; i < block_size; ++i) { size_t j = 4, k = i; while (j--) { block_str[i * 4 + j] = k % 10 + '0'; k /= 10; } } } static constexpr size_t S_integer_digits(uint64_t n) { if (n >= power10[10]) { if (n >= power10[19]) return 20; if (n >= power10[18]) return 19; if (n >= power10[17]) return 18; if (n >= power10[16]) return 17; if (n >= power10[15]) return 16; if (n >= power10[14]) return 15; if (n >= power10[13]) return 14; if (n >= power10[12]) return 13; if (n >= power10[11]) return 12; return 11; } else { if (n >= power10[9]) return 10; if (n >= power10[8]) return 9; if (n >= power10[7]) return 8; if (n >= power10[6]) return 7; if (n >= power10[5]) return 6; if (n >= power10[4]) return 5; if (n >= power10[3]) return 4; if (n >= power10[2]) return 3; if (n >= power10[1]) return 2; return 1; } } public: printer() { M_precompute(); } ~printer() { M_flush(); } void print(char c) { outbuf[M_out_pos++] = c; if (__builtin_expect(M_out_pos == buf_size, 0)) M_flush(); } void print(const char *s) { while (*s != 0) { outbuf[M_out_pos++] = *s++; if (M_out_pos == buf_size) M_flush(); } } void print(const std::string &s) { for (auto c: s) { outbuf[M_out_pos++] = c; if (M_out_pos == buf_size) M_flush(); } } template typename std::enable_if::value, void>::type print(T x) { if (__builtin_expect(M_out_pos + integer_size >= buf_size, 0)) M_flush(); if (x < 0) print('-'), x = -x; size_t digit = S_integer_digits(x); size_t len = digit; while (len >= 4) { len -= 4; memcpy(outbuf + M_out_pos + len, block_str + (x % block_size) * 4, 4); x /= 10000; } memcpy(outbuf + M_out_pos, block_str + x * 4 + 4 - len, len); M_out_pos += digit; } template void print(const T &x, const Args&... args) { print(x); print(' '); print(args...); } template void println(const Args&... args) { print(args...); print('\n'); } template printer& operator << (const T &x) { print(x); return *this; } }; }; /** * @title Fast Input/Output */ #line 57 "main.cpp" using i32 = int32_t; using i64 = int64_t; using u32 = uint32_t; using u64 = uint64_t; constexpr i32 inf32 = (i32(1) << 30) - 1; constexpr i64 inf64 = (i64(1) << 62) - 1; struct edge_t { i32 to; i64 cap; i32 rev; }; fast_io::scanner cin; fast_io::printer cout; class Stack { private: const int N, H; std::vector node; public: Stack(const int _N, const int _H) : N(_N), H(_H), node(N+H){ clear(); } bool empty(const int h) const { return node[N+h] == N+h; } int top(const int h) const { return node[N+h]; } void pop(const int h){ node[N+h] = node[node[N+h]]; } void push(const int h, const int u){ node[u] = node[N+h], node[N+h] = u; } void clear(){ std::iota(node.begin() + N, node.end(), N); } }; class List { public: struct node { int prev, next; }; const int N, H; std::vector dat; List(const int _N, const int _H) : N(_N), H(_H), dat(N+H){ clear(); } bool empty(const int h) const { return (dat[N+h].next == N+h); } bool more_one(const int h) const { return dat[N+h].prev != dat[N+h].next; } void insert(const int h, const int u){ dat[u].prev = dat[N+h].prev, dat[u].next = N+h; dat[dat[N+h].prev].next = u, dat[N+h].prev = u; } void erase(const int u){ dat[dat[u].prev].next = dat[u].next, dat[dat[u].next].prev = dat[u].prev; } void clear(){ for(int i = N; i < N+H; ++i) dat[i].prev = dat[i].next = i; } }; int main() { i32 H, W; cin.scan(H, W); i32 V = H + W + 2; i32 source = H + W, sink = H + W + 1; std::vector> graph(V); auto add_edge = [&](i32 u, i32 v, i64 c) { graph[u].push_back(edge_t{ v, c, (i32) graph[v].size() }); graph[v].push_back(edge_t{ u, 0, (i32) graph[u].size() - 1 }); }; std::vector accum(H); for (auto i: range(0, H)) { for (auto j: range(0, W)) { i32 g; cin.scan(g); accum[i] += g; add_edge(i, H + j, g); } } i64 sum = 0; for (auto i: range(0, H)) { i64 r; cin.scan(r); i64 min = std::min(accum[i], r); sum += r - min; add_edge(source, i, accum[i] - min); } for (auto i: range(0, W)) { i64 r; cin.scan(r); sum += r; add_edge(H + i, sink, r); } i32 min_gap, max_active; Stack active(V, V); List all(V, V); std::vector height(V), seen(V); std::vector excess(V); i32 counter = 0; auto push = [&](auto u, edge_t &e) { // Push flow from the node. i64 flow = std::min(e.cap, excess[u]); e.cap -= flow; graph[e.to][e.rev].cap += flow; excess[u] -= flow; excess[e.to] += flow; }; auto relabel = [&](auto u) { // Relabel the node so that there will be an admissible edge. ++counter; i32 min = V + 1; for (auto &e: graph[u]) { if (e.cap > 0) { chmin(min, height[e.to] + 1); } } height[u] = min; }; auto reverse_bfs = [&] { // Compute exact heights. std::fill(height.begin(), height.end(), V + 1); height[sink] = 0; std::queue que; que.push(sink); while (!que.empty()) { i32 u = que.front(); que.pop(); for (auto e: graph[u]) { if (graph[e.to][e.rev].cap > 0) { if (chmin(height[e.to], height[u] + 1)) { que.push(e.to); } } } } }; auto set_active = [&] { // Count nodes with each height and set active nodes. min_gap = V; max_active = 0; active.clear(); all.clear(); for (auto u: range(0, V)) { if (height[u] < V) { if (excess[u] > 0 && u != sink) { active.push(height[u], u); chmax(max_active, height[u]); } all.insert(height[u], u); } } for (auto h: range(0, V)) { if (all.empty(h)) { min_gap = h; break; } } }; auto discharge = [&](auto u) { // Apply push/relabel until the node becomes inactive. while (true) { auto &e = graph[u][seen[u]]; if (e.cap > 0 && height[u] == height[e.to] + 1) { { if (excess[e.to] == 0 && e.to != sink) { active.push(height[e.to], e.to); chmax(max_active, height[e.to]); } } push(u, e); if (excess[u] == 0) { break; } } seen[u]++; if (seen[u] == graph[u].size()) { seen[u] = 0; if (all.more_one(height[u])) { all.erase(u); relabel(u); if (height[u] > min_gap) { height[u] = V + 1; break; } if (height[u] == min_gap) { min_gap++; } all.insert(height[u], u); } else { for (auto i: range(height[u], min_gap)) { for (i32 id = all.dat[V + i].next; id < V; id = all.dat[id].next) { height[id] = V + 1; } all.dat[V + i].prev = all.dat[V + i].next = V + i; } break; } } } }; { // Preprocess reverse_bfs(); if (height[source] == V + 1) { cout.println(sum); return 0; } for (auto &e: graph[source]) { excess[source] += e.cap; push(source, e); } height[source] = V; set_active(); } { // Main Process while (max_active > 0) { if (active.empty(max_active)) { --max_active; continue; } const auto u = active.top(max_active); active.pop(max_active); discharge(u); // if (counter >= V * 4) { // counter -= V * 4; // reverse_bfs(); // set_active(); // } chmin(max_active, min_gap - 1); } } cout.println(sum - excess[sink]); return 0; }