ARC142E
性质,巨大多性质。
设 mnx=max(x,y)∈E{min(bx,by)},首先让 ai→mni(如果不够)。
关键性质:记 X 表示所有 bx>ax 的集合,Y={1,⋯,n}∖X。那么对于一条边,至少有一个点属于 Y。
也就是说,如果一条边 (x,y) 不满足条件,假设 x∈X,我们让它合法的条件就是要么使得 ax→bx,要么使得 ay→bx。
记 S 为源点,T 为汇点,(u,v,w) 表示网络中 u→v 容量为 w 的边。
考虑网络流建图:
- i∈X,(S,i,bi−ai)
- i∈Y,j∈[1,100],((i,j),T,1)
- i∈Y,j∈[2,100],((i,j),(i,j−1),∞)
- (x,y)∈E,x∈X,y∈Y,(x,(y,bx−ay),∞),如果 ay<bx。
其中 (i,j) 表示一类特殊的点,共 100n 个。
这样建图之后跑一遍最小割就是答案。
Code:
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
typedef long long ll;
const int N = 105, inf = 0x3f3f3f3f;
namespace F {
const int N = 20005, M = N * 20;
int S, T;
int head[N], now[N], ver[M], wei[M], nxt[M], cnt = 1;
int d[N];
void add(int u, int v, int w) {
ver[++cnt] = v, wei[cnt] = w, nxt[cnt] = head[u], head[u] = cnt;
ver[++cnt] = u, wei[cnt] = 0, nxt[cnt] = head[v], head[v] = cnt;
}
queue <int> q;
bool bfs() {
memset(d, 0, sizeof d), d[S] = 1;
now[S] = head[S];
while (q.size()) q.pop(); q.push(S);
while (!q.empty()) {
int u = q.front(); q.pop();
for (int i = head[u]; i; i = nxt[i]) {
int v = ver[i], w = wei[i];
if (w && !d[v]) {
d[v] = d[u] + 1, now[v] = head[v], q.push(v);
if (v == T) return true;
}
}
}
return false;
}
int dinic(int u, int flow) {
if (u == T) return flow;
int res = flow;
for (int &i = now[u]; i; i = nxt[i]) {
int v = ver[i], w = wei[i];
if (w && d[v] == d[u] + 1) {
int k = dinic(v, min(res, w));
if (!k) d[v] = 0;
wei[i] -= k, wei[i ^ 1] += k, res -= k;
}
if (!res) break;
}
return flow - res;
}
ll maxflow() {
ll res = 0; int flow;
while (bfs())
while (flow = dinic(S, inf)) res += flow;
return res;
}
}
int n, m;
int a[N], b[N], mn[N];
int ans;
vector <int> G[N];
bool flag[N];
void chkmax(int &a, int b) { if (a < b) a = b; }
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) scanf("%d%d", &a[i], &b[i]);
scanf("%d", &m);
for (int i = 1, u, v; i <= m; ++i) scanf("%d%d", &u, &v), G[u].pb(v), G[v].pb(u), chkmax(mn[u], min(b[u], b[v])), chkmax(mn[v], min(b[u], b[v]));
for (int i = 1; i <= n; ++i) if (a[i] < mn[i]) ans += mn[i] - a[i], a[i] = mn[i];
for (int i = 1; i <= n; ++i) if (a[i] < b[i]) flag[i] = 1;
F::S = 0, F::T = n * 101 + 1;
for (int x = 1; x <= n; ++x) {
if (flag[x]) {
F::add(F::S, x, b[x] - a[x]);
for (auto y : G[x])
if (!flag[y] && b[x] > a[y]) F::add(x, n + 100 * (y - 1) + (b[x] - a[y]), inf);
}
else {
for (int i = 1; i <= 100; ++i) {
F::add(n + 100 * (x - 1) + i, F::T, 1);
if (i > 1) F::add(n + 100 * (x - 1) + i, n + 100 * (x - 1) + i - 1, inf);
}
}
}
printf("%lld", ans + F::maxflow());
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话