bzoj 4873 [Shoi2017] sushi restaurant maximum weight closure graph

Problem surface

Title gate

solution

  • It is found that every combination of sushi can only be calculated once, and there are some dependencies: for example, if [l,r][l,r][l,r] is selected, all its subranges must be selected.
  • This inspires us to solve the problem by using the maximum weight closed subgraph. It is advisable to consider all intervals as points and construct a graph in the way of maximum weighted closed subgraph. Of course, for interval [l,r][l,r][l,r], we don't have to connect to all subintervals, just connect to [l,r − 1][l,r-1][l,r − 1] and [l+1,r][l+1,r][l+1,r].
  • Then consider how to deal with mx2+cxmx^2+cxmx2+cx. You can build a point for each type of x x x, and then connect all the points [I, I, I, I] of a[i]=xa[i]=xa[i]=x to xxx, and then connect xxx to TTT to an edge with a capacity of mx2mx^2mx2, which will solve the problem of mx2mx^2mx2. Then, we deal with cxcx, as long as we connect all the points of a[i]=xa[i]=xa[i]=x to TTT with an edge of xxx capacity.
  • Considering that this is a minimum cut problem, the algorithm is obviously correct.

Code

#include <bits/stdc++.h>
#define ll long long
using namespace std;
template <typename T> void read(T &x) {
	x = 0; int f = 1; char c = getchar();
	while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
	while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
const int N = 110, M = N * N, inf = 1 << 30;
int cnt, a[N], b[N], d[N][N], num[N][N], l[M], cur[M], head[M];
struct Edge {int next, num, c;} e[N * N * N];
void add(int x, int y, int c) {e[++cnt] = (Edge) {head[x], y, c}, head[x] = cnt;}
void Add(int x, int y, int c) {add(x, y, c), add(y, x, 0);}
bool bfs(int s, int t) {
	for (int i = s; i <= t; i++) l[i] = -1;
	queue <int> q; q.push(s), l[s] = 0;
	while (!q.empty()) {
		int x = q.front(); q.pop();
		for (int p = head[x]; p; p = e[p].next) {
			int y = e[p].num, c = e[p].c;
			if (c && l[y] == -1) q.push(y), l[y] = l[x] + 1;
		}
	}
	return l[t] != -1;
}
int dfs(int x, int t, int lim) {
	if (x == t) return lim; int ret = 0;
	for (int &p = cur[x]; p; p = e[p].next) {
		int y = e[p].num, c = e[p].c;
		if (l[y] == l[x] + 1 && c) {
			int w = dfs(y, t, min(lim - ret, c));
			e[p].c -= w, e[p ^ 1].c += w, ret += w;
			if (ret == lim) return ret;
		}
	}
	if (!ret) l[x] = -1; return ret;
}
int dinic(int s, int t) {
	int ret = 0;
	while (bfs(s, t)) {
		memcpy(cur, head, sizeof(cur));
		ret += dfs(s, t, inf);
	}
	return ret;
}
int main() {
	int n, m, tot = 0; read(n), read(m); cnt = 1;
	for (int i = 1; i <= n; i++) read(a[i]);
	for (int i = 1; i <= n; i++)
		for (int j = i; j <= n; j++)
			read(d[i][j]), num[i][j] = ++tot;
	int s = 0, t = n + tot + 1; ll ans = 0;
	for (int i = 1; i <= n; i++)
		for (int j = i; j <= n; j++) {
			if (d[i][j] > 0) ans += d[i][j], Add(s, num[i][j], d[i][j]);
				else Add(num[i][j], t, -d[i][j]);
			if (i < j) Add(num[i][j], num[i][j - 1], inf), Add(num[i][j], num[i + 1][j], inf);
		}
	map <int, int> h; h.clear();
	for (int i = 1; i <= n; i++)
		if (h.count(a[i])) b[i] = h[a[i]];
			else b[i] = h[a[i]] = ++tot, Add(tot, t, m * a[i] * a[i]);
	for (int i = 1; i <= n; i++) Add(num[i][i], b[i], inf), Add(num[i][i], t, a[i]);
	cout << ans - dinic(s, t) << "\n";
	return 0;
}

Posted by jaxdevil on Sat, 07 Dec 2019 04:54:35 -0800