Solution -「AGC 031E」Snuke the Phantom Thief
\(\mathscr{Description}\)
Link.
在一个网格图内有 \(n\) 个格子有正价值,给出四种限制:横 / 纵坐标不大于 / 不小于 \(a\) 的格子不能选超过 \(b\) 个。求能选出格子价值之和的最大值。
\(n\le80\),坐标范围 \(1\le X\le100\),限制数量 \(m\le320\)。
\(\mathscr{Solution}\)
你看出来是网络流,但应当留意,图本身也许不是全部。
大概感知一下,感觉是一个源点-横坐标-价值点-纵坐标-汇点的模型,但很难同时处理坐标上的前缀和限制与后缀和限制。怎么办?枚举最终选出的格子数 \(k\),它给我们带来了额外条件——对后缀的限制可以化归为对前缀的限制。
具体地,以横坐标为例,先人为限制按横坐标升序选格子。对于 \(b<k\) 的某个限制,若限制前缀不超过 \(b\) 个,相当于选出的第 \(b+1..k\) 个格子的横坐标都得 \(>a\);若限制后缀不超过 \(b\) 个,相当于选出的第 \(1..k-b\) 个格子的横坐标都得 \(<a\)。纵坐标同理,规定纵坐标升序选即可,二者只是考虑角度不同,并不矛盾。依此跑费用流,若满流,用最大费用更新答案即可。
复杂度 \(\mathcal O(n\operatorname{Dinic}(n,n^2))\),当然边数可以优化至 \(\mathcal O(n\log n)\)。
\(\mathscr{Code}\)
/*+Rainybunny+*/
#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
#define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i)
typedef long long LL;
typedef std::pair<int, LL> PIL;
#define fi first
#define se second
template <typename Tp>
inline void chkmin(Tp& u, const Tp& v) { v < u && (u = v, 0); }
template <typename Tp>
inline void chkmax(Tp& u, const Tp& v) { u < v && (u = v, 0); }
template <typename Tp>
inline Tp imin(const Tp& u, const Tp& v) { return u < v ? u : v; }
template <typename Tp>
inline Tp imax(const Tp& u, const Tp& v) { return u < v ? v : u; }
const int MAXN = 80, MAXM = 320, MAXX = 100, IINF = 0x3f3f3f3f;
const LL LINF = 1ll << 60;
namespace FG {
const int MAXND = MAXN * 2 + MAXX * 2 + 2;
const int MAXEG = MAXN * MAXN * 2 + MAXN * 3;
int S, T, ecnt = 1, head[MAXND + 5], curh[MAXND + 5];
LL dis[MAXND + 5];
struct Edge { int to, flw; LL cst; int nxt; } graph[MAXEG * 2 + 5];
inline void clear() {
ecnt = 1;
rep (i, S, T) head[i] = 0;
}
inline void link(const int s, const int t, const int f, const LL c) {
// printf("%d %d %d,%lld\n", s, t, f, c);
graph[++ecnt] = { t, f, c, head[s] }, head[s] = ecnt;
graph[++ecnt] = { s, 0, -c, head[t] }, head[t] = ecnt;
}
inline bool spfa() {
static std::queue<int> que;
static bool inq[MAXND + 5];
rep (i, S, T) dis[i] = LINF;
dis[S] = 0, que.push(S);
while (!que.empty()) {
int u = que.front(); que.pop(), inq[u] = false;
for (int i = head[u], v; i; i = graph[i].nxt) {
if (graph[i].flw && dis[v = graph[i].to] > dis[u] + graph[i].cst) {
dis[v] = dis[u] + graph[i].cst;
if (!inq[v]) que.push(v), inq[v] = true;
}
}
}
return dis[T] != LINF;
}
inline PIL augment(const int u, int iflw) {
if (u == T) return { iflw, 0 };
static bool instk[MAXND + 5]; instk[u] = true;
PIL ret(0, 0);
for (int &i = curh[u], v; i; i = graph[i].nxt) {
if (graph[i].flw && !instk[v = graph[i].to]
&& dis[v] == dis[u] + graph[i].cst) {
PIL t(augment(v, std::min(iflw, graph[i].flw)));
ret.fi += t.fi, ret.se += t.se + t.fi * graph[i].cst;
graph[i].flw -= t.fi, graph[i ^ 1].flw += t.fi, iflw -= t.fi;
if (!iflw) break;
}
}
if (!ret.fi) dis[u] = LINF;
return instk[u] = false, ret;
}
inline PIL dinic() {
PIL ret(0, 0);
while (spfa()) {
rep (i, S, T) curh[i] = head[i];
PIL t(augment(S, IINF));
ret.fi += t.fi, ret.se += t.se;
}
return ret;
}
} // namespace FG.
int n, m, jx[MAXN + 5], jy[MAXN + 5];
int lefx[MAXN + 5], rigx[MAXN + 5], lefy[MAXN + 5], rigy[MAXN + 5];
LL jv[MAXN + 5];
struct Restrict { int op, a, b; } lim[MAXM + 5];
int main() {
scanf("%d", &n);
rep (i, 1, n) scanf("%d %d %lld", &jx[i], &jy[i], &jv[i]);
scanf("%d", &m);
rep (i, 1, m) {
char op[5];
scanf("%s %d %d", op, &lim[i].a, &lim[i].b), lim[i].op = op[0];
}
LL ans = 0;
rep (x, 1, n) {
// x = 4; // debug.
FG::clear();
FG::S = 0, FG::T = 2 * x + 2 * n + 1;
rep (i, 1, x) {
FG::link(FG::S, i, 1, 0);
FG::link(i + x, FG::T, 1, 0);
}
rep (i, 1, n) FG::link(i + 2 * x, i + n + 2 * x, 1, -jv[i]);
rep (i, 1, x) lefx[i] = lefy[i] = 1, rigx[i] = rigy[i] = MAXX;
rep (i, 1, m) if (lim[i].b < x) {
if (lim[i].op == 'L') chkmax(lefx[lim[i].b + 1], lim[i].a + 1);
if (lim[i].op == 'R') chkmin(rigx[x - lim[i].b], lim[i].a - 1);
if (lim[i].op == 'U') chkmin(rigy[x - lim[i].b], lim[i].a - 1);
if (lim[i].op == 'D') chkmax(lefy[lim[i].b + 1], lim[i].a + 1);
}
rep (i, 2, x) {
chkmax(lefx[i], lefx[i - 1]), chkmax(lefy[i], lefy[i - 1]);
}
per (i, x - 1, 1) {
chkmin(rigx[i], rigx[i + 1]), chkmin(rigy[i], rigy[i + 1]);
}
rep (i, 1, x) {
rep (j, 1, n) {
if (lefx[i] <= jx[j] && jx[j] <= rigx[i]) {
FG::link(i, j + 2 * x, 1, 0);
}
if (lefy[i] <= jy[j] && jy[j] <= rigy[i]) {
FG::link(j + n + 2 * x, i + x, 1, 0);
}
}
}
PIL res(FG::dinic());
if (res.fi == x) chkmax(ans, -res.se);
// break; // debug
}
printf("%lld\n", ans);
return 0;
}
Solution -「AGC 031E」Snuke the Phantom Thief的更多相关文章
- Solution -「AGC 036D」「AT 5147」Negative Cycle
\(\mathcal{Descriprtion}\) Link. 在一个含 \(n\) 个结点的有向图中,存在边 \(\lang i,i+1,0\rang\),它们不能被删除:还有边 \(\l ...
- Solution -「AGC 016F」Games on DAG
\(\mathcal{Description}\) Link. 给定一个含 \(n\) 个点 \(m\) 条边的 DAG,有两枚初始在 1 号点和 2 号点的棋子.两人博弈,轮流移动其中一枚棋 ...
- Solution -「AGC 026D」Histogram Coloring
\(\mathcal{Description}\) Link. 有 \(n\) 列下底对齐的方格纸排成一行,第 \(i\) 列有 \(h_i\) 个方格.将每个方格染成黑色或白色,求使得任意完 ...
- Solution -「AGC 004E」「AT 2045」Salvage Robots
\(\mathcal{Description}\) Link. 有一个 \(n\times m\) 的网格.每个格子要么是空的,要么有一个机器人,要么是一个出口(仅有一个).每次可以命令所有机 ...
- Solution -「AGC 012F」「AT 2366」Prefix Median
\(\mathcal{Description}\) Link. 给定序列 \(\{a_{2n-1}\}\),将 \(\{a_{2n-1}\}\) 按任意顺序排列后,令序列 \(b_i\) 为前 ...
- Solution -「AGC 010C」「AT 2304」Cleaning
\(\mathcal{Description}\) Link. 给定一棵 \(n\) 个点的无根树,点有点权,每次选择两个不同的叶子,使它们间的简单路径的所有点权 \(-1\),问能否将所有点 ...
- Solution -「AGC 019E」「AT 2704」Shuffle and Swap
\(\mathcal{Description}\) Link. 给定 \(01\) 序列 \(\{A_n\}\) 和 \(\{B_n\}\),其中 \(1\) 的个数均为 \(k\).记 \( ...
- Solution -「AGC 019F」「AT 2705」Yes or No
\(\mathcal{Description}\) Link. 有 \(n+m\) 个问题,其中 \(n\) 个答案为 yes,\(m\) 个答案为 no.每次你需要回答一个问题,然后得知这个 ...
- Solution -「AGC 013E」「AT 2371」Placing Squares
\(\mathcal{Description}\) Link. 给定一个长度为 \(n\) 的木板,木板上有 \(m\) 个标记点,第 \(i\) 个标记点距离木板左端点的距离为 \(x_i\ ...
- Solution -「AGC 003D」「AT 2004」Anticube
\(\mathcal{Description}\) Link. 给定 \(n\) 个数 \(a_i\),要求从中选出最多的数,满足任意两个数之积都不是完全立方数. \(n\le10^5\) ...
随机推荐
- 狂神说-Docker基础-学习笔记-07 容器数据卷
狂神说-Docker基础-学习笔记-07 容器数据卷 视频地址:https://www.bilibili.com/video/BV1og4y1q7M4?p=21 什么是容器数据卷 运行时数据都在容器中 ...
- 全面解释人工智能LLM模型的真实工作原理(三)
前一篇:<全面解释人工智能LLM模型的真实工作原理(二)> 序言:前面两节中,我们介绍了大语言模型的设计图和实现了一个能够生成自然语言的神经网络.这正是现代先进人工智能语言模型的雏形.不过 ...
- DRF-Serializers序列化器组件源码分析及改编
1. 源码分析 注意:以下代码片段为方便理解已进行简化,只保留了与序列化功能相关的代码 序列化的源码中涉及到了元类的概念,我在这里简单说明一下:元类(metaclass)是一个高级概念,用于定义类的创 ...
- 【FAQ】HarmonyOS SDK 闭源开放能力 —Push Kit(4)
1.问题描述: 目前华为推送API使用的是v2或者v1版本,请问目前最新的鸿蒙next使用v3版本是否兼容v2或者v1,反过来将v2或者v1的api可以推送鸿蒙next的设备吗? 解决方案: v3接口 ...
- 遗传算法+强化学习—TPG—Emergent Tangled Graph Representations for Atari Game Playing Agents_2
最近在看进化算法在强化学习(RL)领域的一些应用,有些论文中将使用进化算法解决强化学习问题的算法归为非强化学习算法,然而又有些论文把使用进化算法解决强化学习问题的算法归为强化学习算法,不过更多的论文是 ...
- 强化学习:gym下atari游戏环境的官方文档地址
2024年10月16日 共建议查看两个历史上的官方地址: https://ale.farama.org/ https://www.gymlibrary.dev/ 最新官方地址: https://ale ...
- MobaXterm连接Ensp回车显示^M,无法敲回车并且报错
最近,在使用MobaXterm连接ensp的时候,发现输入回车键,却不能出现回车的效果,反而打出了^M字符. 临时解决办法: 永久解决办法: 加入以下三行,可以永久关闭回显 [MottyOptions ...
- 鸿蒙NEXT开发案例:转盘
[1]引言(完整代码在最后面) 在鸿蒙NEXT系统中,开发一个有趣且实用的转盘应用不仅可以提升用户体验,还能展示鸿蒙系统的强大功能.本文将详细介绍如何使用鸿蒙NEXT系统开发一个转盘应用,涵盖从组件定 ...
- getent使用小结
转载请注明出处: getent 是一个用于访问系统数据库的命令,通常用于获取与网络有关的信息,比如用户.组.主机名.服务等.这个命令是 Linux 和 Unix 系统中非常有用的工具,可以用来查询多种 ...
- 《前端运维》五、k8s--2pod、services与Ingress部署
前一篇啊,我们学完了基本的配置.这一篇,我们来看下服务部署的配置.我们先来看张图,理解下k8s的应用场景和调用流程: 看上图,首先,master是控制节点,负责编排.管理.调度用户提交的作业.kube ...