Loading

MX galaxy Day11

P3749 [六省联考 2017] 寿司餐厅

\(\boldsymbol{最大权闭合子图}\)
将每个区间作为点,每个区间选了其子区间一定要选。
对于 \(cx\) ,将每个长度为 \(1\) 的区间的贡献减去那种颜色的编号,然后正常处理即可。
至于 \(mx^2\) ,我们将每个点向一个代表其颜色的虚点连边,虚点向汇点连 \(mx^2\) 的边。
意味着,只要有一个点与源点连通,就需要耗费 \(mx^2\) 的代价。

点击查看

#include <bits/stdc++.h>
#define lep(i, a, b) for (int i = a; i <= b; ++i)
#define rep(i, a, b) for (int i = a; i >= b; --i)

const int _ = 3e6 + 7;
const int __ = 1e3;
typedef long long ll;
typedef std::pair<int, int> PII;
const ll inf = 1e18;

struct edge { int v, n; ll c; }e[_]; int H[_], cur[_], cnte = 1;
int n, m, a[_], dep[_], s, t, idx, d[__][__]; ll ans;
std::map<PII, int> Nam;

void Add(int u, int v, ll c) { if (u == s) ans += c; e[++cnte] = { v, H[u], c }, H[u] = cnte, e[++cnte] = { u, H[v], 0 }, H[v] = cnte; }
bool bfs() { std::queue <int> q;
	lep(i, 1, idx) dep[i] = 0;
	dep[s] = 1, q.push(s);
	while (!q.empty()) {
		int u = q.front(); q.pop();
		if (u == t) return true;
		for (int i = H[u], v = e[i].v; i; i = e[i].n, v = e[i].v)
			if (!dep[v] and e[i].c > 0) dep[v] = dep[u] + 1, q.push(v);
	}
	return false;
}
ll dfs(int u, ll total) {
	if (u == t or !total) return total;
	ll res = 0, f;
	for (int i = cur[u], v = e[i].v; i; i = e[i].n, v = e[i].v) { cur[u] = i;
		if (e[i].c > 0 and dep[v] == dep[u] + 1)
			f = dfs(v, std::min(total, e[i].c)),
			e[i].c -= f, e[i ^ 1].c += f, res += f, total -= f;
	}
	return res;
}
void Dinic() {
	while (bfs()) {
		lep(i, 1, idx) cur[i] = H[i];
		ans -= dfs(s, inf);
	}
}
int Id(int x, int y) { return Nam[{x, y}] ? Nam[{x, y}] : Nam[{x, y}] = ++idx; }
void Init() {
	s = ++idx, t = ++idx;
	lep(i, 1, n) lep(j, i + 1, n) {
		if (d[i][j] >= 0) Add(s, Id(i, j), d[i][j]);
		else Add(Id(i, j), t, -d[i][j]);
		Add(Id(i, j), Id(i + 1, j), inf), Add(Id(i, j), Id(i, j - 1), inf);
	}
	lep(i, 1, n) { ll w = d[i][i] - a[i];
		if (w >= 0) Add(s, Id(i, i), w);
		else Add(Id(i, i), t, -w);
		Add(Id(i, i), Id(n + 1, a[i]), inf);
	}
	lep(i, 1, 1000) Add(Id(n + 1, i), t, 1ll * m * i * i);
}

int main() {
	scanf("%d%d", & n, & m);
	lep(i, 1, n) scanf("%d", a + i);
	lep(i, 1, n) lep(j, i, n) scanf("%d", d[i] + j);
	Init(), Dinic();
	printf("%lld\n", ans);
	return 0;
}

P4313 文理分科

将每个点与限制相关的连通块按照黑白分开。
转换成最小割模型。
将每个白点向互斥的黑点连 \(inf\) 边,每个白色连通块向互斥的黑点连 \(inf\) 边。
每个白点向互斥的黑色连通块连 \(inf\) 边,每个白色连通块向互斥的黑色连通块连 \(inf\) 边。

点击查看

#include <bits/stdc++.h>
#define lep(i, a, b) for (int i = a; i <= b; ++i)
#define rep(i, a, b) for (int i = a; i >= b; --i)
#define ABS(x) ((x) > 0 ? (x) : -(x))

const int _ = 3e6 + 7;
const int __ = 100 + 7;
const int inf = 2e9;
typedef long long ll;
typedef std::pair<int, int> PII;

struct edge { int v, n, c; }e[_]; int H[_], cur[_], cnte = 1;
int n, m, dep[_], s, t, idx; ll ans;
int a[__][__], b[__][__], A[__][__], B[__][__];
int di[5] = { 0, 0, 0, 1, -1 };
int dj[5] = { 1, -1, 0, 0, 0 };
int Di[13] = { 0, 0, 0, 1, 1, 1, -1, -1, -1, 0, 0, 2, -2 };
int Dj[13] = { 0, 1, -1, 0, 1, -1, 0, 1, -1, 2, -2, 0, 0 };
std::map<PII, int> Nam;

void Add(int u, int v, int c) { e[++cnte] = { v, H[u], c }, H[u] = cnte, e[++cnte] = { u, H[v], 0 }, H[v] = cnte; }
bool bfs() { std::queue <int> q;
	lep(i, 1, idx) dep[i] = 0;
	dep[s] = 1, q.push(s);
	while (!q.empty()) {
		int u = q.front(); q.pop();
		if (u == t) return true;
		for (int i = H[u], v = e[i].v; i; i = e[i].n, v = e[i].v)
			if (!dep[v] and e[i].c > 0) dep[v] = dep[u] + 1, q.push(v);
	}
	return false;
}
int dfs(int u, int total) {
	if (u == t or !total) return total;
	int res = 0, f;
	for (int i = cur[u], v = e[i].v; i; i = e[i].n, v = e[i].v) { cur[u] = i;
		if (e[i].c > 0 and dep[v] == dep[u] + 1) {
			f = dfs(v, std::min(total, e[i].c));
			if (!f) { dep[v] = 0; continue; }
			e[i].c -= f, e[i ^ 1].c += f, res += f, total -= f;
			if (!total) break;
		}
	}
	return res;
}
void Dinic() {
	while (bfs()) {
		lep(i, 1, idx) cur[i] = H[i];
		ans -= dfs(s, inf);
	}
}
int Id(int op, int x, int y) { return op * n * m + (x - 1) * m + y; }
void Init() {
	s = 4 * n * m + 1, t = idx = s + 1;
	lep(x, 1, n) lep(y, 1, m) {
		Add(s, Id(0, x, y), a[x][y]), Add(Id(1, x, y), t, b[x][y]);
		Add(Id(0, x, y), Id(1, x, y), inf);
		Add(s, Id(2, x, y), A[x][y]), Add(Id(3, x, y), t, B[x][y]);
		lep(k, 0, 4) { int dx = x + di[k], dy = y + dj[k];
			if (dx < 1 or dy < 1 or dx > n or dy > m) continue;
			Add(Id(0, x, y), Id(3, dx, dy), inf),
			Add(Id(2, x, y), Id(1, dx, dy), inf);
		}
		lep(k, 0, 12) { int dx = x + Di[k], dy = y + Dj[k];
			if (dx < 1 or dy < 1 or dx > n or dy > m) continue;
			Add(Id(2, x, y), Id(3, dx, dy), inf);
		}
	}
}

int main() {
	scanf("%d%d", & n, & m);
	lep(i, 1, n) lep(j, 1, m) scanf("%d", a[i] + j), ans += a[i][j];
	lep(i, 1, n) lep(j, 1, m) scanf("%d", b[i] + j), ans += b[i][j];
	lep(i, 1, n) lep(j, 1, m) scanf("%d", A[i] + j), ans += A[i][j];
	lep(i, 1, n) lep(j, 1, m) scanf("%d", B[i] + j), ans += B[i][j];
	Init(), Dinic();
	printf("%lld\n", ans);
	return 0;
}

P9879 [EC Final 2021] Check Pattern is Good

容易发现网格图是个二分图,可以将其进行黑白染色。
将每个黑色点的位置的 W , B 翻转,那么产生贡献的连通块形如:

\[\begin{matrix} WW\\ WW \end{matrix} \]

或者

\[\begin{matrix} BB\\ BB \end{matrix} \]

类似上一题建模即可。

点击查看

#include <bits/stdc++.h>
#define lep(i, a, b) for (int i = a; i <= b; ++i)
#define rep(i, a, b) for (int i = a; i >= b; --i)
#define ep(i, u) for (int i = H[u], v = e[i].v; i ; i = e[i].n, v = e[i].v)

typedef long long ll;
const int _ = 1e6 + 7;
const int inf = 2e9;

struct edge { int v, n, c; }e[_]; int H[_], cur[_], cnte = 1;
int T, n, m, s, t, val[110][110], dep[_], ans;
char c[_];
int di[9] = { 0, -1, 1, 0, -1, 1, 0, -1, 1 };
int dj[9] = { 0, -1, 1, -1, 1, 0, 1, 0, -1 };

int id(int k, int x, int y) { return k * (n - 1) * (m - 1) + (x - 1) * (m - 1) + y; }
void Add(int u, int v, int c) { if (c != inf) ans += c; e[++cnte] = { v, H[u], c }, H[u] = cnte; }
bool Bfs() { std::queue <int> d;
    lep(i, s, t) dep[i] = 0, cur[i] = H[i]; dep[s] = 1;
    d.push(s);
    while (!d.empty()) {
        int u = d.front(); d.pop();
        ep(i, u) if (e[i].c > 0 and !dep[v]) {
            dep[v] = dep[u] + 1;
            d.push(v);
            if (v == t) return true;
        }
    }
    return false;
}
int Dfs(int u, int want) {
    if (u == t) return want;
    int tot = 0, flow;
    for (int i = cur[u], v = e[i].v; i and want; i = e[i].n, v = e[i].v) { cur[u] = i;
        if (e[i].c > 0 and dep[v] == dep[u] + 1) {
            flow = Dfs(v, std::min(want, e[i].c));
            e[i].c -= flow, e[i ^ 1].c += flow,
            tot += flow, want -= flow;
        }
    }
    return tot;
}

int main() {
    scanf("%d", & T);
    while (T--) {
        scanf("%d%d", & n, & m);
        lep(i, 1, n) {
            scanf("%s", c + 1);
            lep(j, 1, m) {
                if (c[j] == '?') val[i][j] = -1;
                else val[i][j] = ((c[j] == 'B') ^ ((i + j) & 1));
            }
        }

        s = 0, t = 2 * (n - 1) * (m - 1) + 1;
        lep(i, 1, n - 1) lep(j, 1, m - 1) {
            bool f0 = false, f1 = false;
            lep(k, 0, 1) lep(t, 0, 1) {
                if (val[i + k][j + t] == 0) f0 = true;
                if (val[i + k][j + t] == 1) f1 = true;
            }
            if (!f1) Add(s, id(0, i, j), !f1), Add(id(0, i, j), s, 0);
            if (!f0) Add(id(1, i, j), t, !f0), Add(id(1, i, j), s, 0);
            lep(k, 0, 8) {
                int dx = i + di[k], dy = j + dj[k];
                if (dx and dy and dx < n and dy < m)
                    Add(id(0, i, j), id(1, dx, dy), inf),
                    Add(id(1, dx, dy), id(0, i, j), 0);
            }
        }
        
        while (Bfs()) ans -= Dfs(s, inf);
        
        lep(i, 1, n - 1) lep(j, 1, m - 1) {
            if (dep[id(0, i, j)])
                val[i][j] = val[i + 1][j] = val[i][j + 1] = val[i + 1][j + 1] = 0;
        }
        
        lep(i, 1, n) lep(j, 1, m) val[i][j] = (((~val[i][j] ? val[i][j] : 1) ^ (i + j)) & 1);
        
        printf("%d\n", ans); ans = 0;
        lep(i, 1, n) {
            lep(j, 1, m) putchar(val[i][j] ? 'B' : 'W');
            putchar('\n');
        }
        lep(i, s, t) H[i] = 0; cnte = 1;
    }
    return 0;
}

P3227 [HNOI2013] 切糕

\(\boldsymbol{切糕模型}\)

如图建模,割掉那条边,就意味着值域选哪个数。
对于每个限制,拆成 \(b-d\le a \le b+d\) ,对于当前值域链,只考虑大于等于的部分。
如图为 \(d=2\) 时的连边。
来看 \(4\)\(2'\) 两个点,意味着如果 \(v4\) 被选了,那么另一条链一定要选一个大于等于 \(v'2\) 的数。

点击查看

#include <bits/stdc++.h>
#define lep(i, a, b) for (int i = a; i <= b; ++i)
#define rep(i, a, b) for (int i = a; i >= b; --i)
#define ABS(x) ((x) > 0 ? (x) : -(x))

const int _ = 3e6 + 7;
const int __ = 100 + 7;
const int inf = 2e9;
typedef long long ll;
typedef std::pair<int, int> PII;

struct edge { int v, n, c; }e[_]; int H[_], cur[_], cnte = 1;
int n, m, c, d, dep[_], s, t, ans;
int v[__][__][__];
int di[4] = { 0, 0, 1, -1 };
int dj[4] = { 1, -1, 0, 0 };

void Add(int u, int v, int c) { e[++cnte] = { v, H[u], c }, H[u] = cnte, e[++cnte] = { u, H[v], 0 }, H[v] = cnte; }
bool bfs() { std::queue <int> q;
	lep(i, s, t) dep[i] = 0;
	dep[s] = 1, q.push(s);
	while (!q.empty()) {
		int u = q.front(); q.pop();
		if (u == t) return true;
		for (int i = H[u], v = e[i].v; i; i = e[i].n, v = e[i].v)
			if (!dep[v] and e[i].c > 0) dep[v] = dep[u] + 1, q.push(v);
	}
	return false;
}
int dfs(int u, int total) {
	if (u == t or !total) return total;
	int res = 0, f;
	for (int i = cur[u], v = e[i].v; i and total; i = e[i].n, v = e[i].v) { cur[u] = i;
		if (e[i].c > 0 and dep[v] == dep[u] + 1) {
			f = dfs(v, std::min(total, e[i].c));
			if (!f) { dep[v] = 0; continue; }
			e[i].c -= f, e[i ^ 1].c += f, res += f, total -= f;
		}
	}
	return res;
}
void Dinic() {
	while (bfs()) {
		lep(i, s, t) cur[i] = H[i];
		ans += dfs(s, inf);
	}
}
int Id(int x, int y, int z) { return (z - 1) * n * m + (x - 1) * m + y; }
void Init() {
	s = 0, t = Id(n, m, c) + 1;
	lep(x, 1, n) lep(y, 1, m) {
		Add(s, Id(x, y, 1), inf);
		lep(r, 1, c - 1) Add(Id(x, y, r), Id(x, y, r + 1), v[x][y][r]);
		Add(Id(x, y, c), t, v[x][y][c]);
		lep(k, 0, 3) { int dx = x + di[k], dy = y + dj[k];
			if (dx < 1 or dy < 1 or dx > n or dy > m) continue;
			lep(r, d + 1, c) Add(Id(x, y, r), Id(dx, dy, r - d), inf);
		}
	}
}

int main() {
	scanf("%d%d%d%d", & n, & m, & c, & d);
	lep(z, 1, c) lep(x, 1, n) lep(y, 1, m)
		scanf("%d", v[x][y] + z);
	Init(), Dinic();
	printf("%d\n", ans);
	return 0;
}

posted @ 2025-07-24 21:59  qkhm  阅读(7)  评论(0)    收藏  举报