【题目链接】

  • BZOJ
  • UOJ

【思路要点】

  • 将所有点按照纵坐标排序,分别处理同一纵坐标的点。
  • 显然,每个点在各个方向上的后继点若存在,是唯一的,先预处理。
  • 记\(f_i\)表示从节点\(i\)出发,能够经过的最多的点数。
  • 若不考虑左右的移动,\(f_i\)就是\(i\)在三个方向上后继结点的\(f\)值的最大值加1,记这个值为\(tmp_i\)。
  • 不妨令同一纵坐标的点横坐标递增,那么有\(f_i=max\{tmp_i,max_{j=1}^{i-1}\{tmp_j+N-j+1\},max_{j=i+1}^{N}\{tmp_j+j\}\}\)。
  • 显然后面两个部分可以用前/后缀最大值优化转移,这样就解决了问题的前两问。
  • 考虑第三问,如果我们知道哪些边可能会出现在前面问题的最优解上,那么我们可以通过有上下界的有源有汇最小流来解决问题,问题在于判断哪些边可能会出现在前面问题的最优解上。
  • 再次DP,记\(g_i\)表示从原点走到点\(i\)至多经过的点数,若从原点出发无法到达\(i\),记\(g_i=-\infty\)。
  • 若不考虑左右的移动,\(g_i\)就是\(i\)在三个方向上后继结点的\(f\)值的最大值加1,记这个值为\(tmp_i\)。
  • 不妨令同一纵坐标的点横坐标递增,那么有\(g_i=max\{tmp_i,max_{j=1}^{i-1}\{tmp_j\}+i,max_{j=i+1}^{N}\{tmp_j\}+N-i+1\}\)。
  • 显然后面两个部分可以用前/后缀最大值优化转移。
  • 求出\(g_i\)后,考虑一条非左右方向的边\((x,y)\),它会出现在答案上当且仅当\(g_y+f_x=Ans\)。
  • 至此,问题得到解决。时间复杂度\(O(NLogN+Dinic(N,N))\)。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 50005;
const int MAXP = 50005;
const int INF = 1e8;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {x = 0; int f = 1;char c = getchar();for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';x *= f;
}
template <typename T> void write(T x) {if (x < 0) x = -x, putchar('-');if (x > 9) write(x / 10);putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {write(x);puts("");
}
struct info {int x, y, home; };
struct edge {int dest; int flow; unsigned home; };
int s, t, olds, oldt, dist[MAXP];
vector <edge> b[MAXP]; unsigned curr[MAXP];
bool cmp(info a, info b) {if (a.y == b.y) return a.x < b.x;else return a.y > b.y;
}
info a[MAXN];
map <int, int> up, lup, rup;
int nxtup[MAXN], nxtlup[MAXN], nxtrup[MAXN];
int tmp[MAXN], ans[MAXN], method[MAXN], tot;
int tnp[MAXN], bns[MAXN];
int dinic(int pos, int limit) {if (pos == t) return limit;int used = 0, tmp;for (unsigned &i = curr[pos]; i < b[pos].size(); i++)if (b[pos][i].flow != 0 && dist[pos] + 1 == dist[b[pos][i].dest] && (tmp = dinic(b[pos][i].dest, min(limit - used, b[pos][i].flow))) != 0) {used += tmp;b[pos][i].flow -= tmp;b[b[pos][i].dest][b[pos][i].home].flow += tmp;if (used == limit) return used;}return used;
}
bool bfs() {static int q[MAXP], l = 0, r = -1;for (int i = 0; i <= r; i++)dist[q[i]] = 0;q[l = r = 0] = s, dist[s] = 1;while (l <= r) {int tmp = q[l++];for (unsigned i = 0; i < b[tmp].size(); i++)if (b[tmp][i].flow != 0 && dist[b[tmp][i].dest] == 0) {q[++r] = b[tmp][i].dest;dist[b[tmp][i].dest] = dist[tmp] + 1;}}return dist[t] != 0;
}
void addedge(int s, int t, int flow) {b[s].push_back((edge) {t, flow, b[t].size()});b[t].push_back((edge) {s, 0, b[s].size() - 1});
}
void addedge(int x, int y) {addedge(x, y, INF);addedge(s, y, 1);addedge(x, t, 1);
}
int main() {int n; read(n);for (int i = 1; i <= n; i++)read(a[i].x), read(a[i].y), a[i].home = i;sort(a + 1, a + n + 1, cmp);int last = 0;for (int i = 1; i <= n; i++) {if (a[i].y == a[i + 1].y) continue;for (int j = last + 1; j <= i; j++) {tmp[j] = 0;if (up.count(a[j].x)) chkmax(tmp[j], up[a[j].x]);if (lup.count(a[j].x + a[j].y)) chkmax(tmp[j], lup[a[j].x + a[j].y]);if (rup.count(a[j].x - a[j].y)) chkmax(tmp[j], rup[a[j].x - a[j].y]);}static int pre[MAXN], suf[MAXN];pre[last] = suf[i + 1] = -INF;for (int j = last + 1; j <= i; j++)pre[j] = max(pre[j - 1], tmp[j] - j);for (int j = i; j >= last + 1; j--)suf[j] = max(suf[j + 1], tmp[j] + j);for (int j = last + 1; j <= i; j++) {ans[j] = tmp[j];chkmax(ans[j], pre[j - 1] + i);chkmax(ans[j], suf[j + 1] - (last + 1));ans[j] += 1;up[a[j].x] = ans[j];lup[a[j].x + a[j].y] = ans[j];rup[a[j].x - a[j].y] = ans[j];}last = i;}int ansval = 0;if (up.count(0)) chkmax(ansval, up[0]);if (lup.count(0)) chkmax(ansval, lup[0]);if (rup.count(0)) chkmax(ansval, rup[0]);writeln(ans[0] = ansval);up.clear(), lup.clear(), rup.clear();last = 0;for (int i = 1; i <= n; i++) {if (a[i].y == a[i + 1].y) continue;for (int j = last + 1; j <= i; j++) {if (up.count(a[j].x)) nxtup[j] = up[a[j].x];if (lup.count(a[j].x + a[j].y)) nxtlup[j] = lup[a[j].x + a[j].y];if (rup.count(a[j].x - a[j].y)) nxtrup[j] = rup[a[j].x - a[j].y];up[a[j].x] = j;lup[a[j].x + a[j].y] = j;rup[a[j].x - a[j].y] = j;}last = i;}nxtup[0] = up[0];nxtlup[0] = lup[0];nxtrup[0] = rup[0];int now = 0;if (nxtup[0] && ans[nxtup[0]] == ansval) now = nxtup[0];else if (nxtlup[0] && ans[nxtlup[0]] == ansval) now = nxtlup[0];else if (nxtrup[0] && ans[nxtrup[0]] == ansval) now = nxtrup[0];while (now != 0) {int l = now, r = now;while (a[l - 1].y == a[now].y) l--;while (a[r + 1].y == a[now].y) r++;static int pre[MAXN], suf[MAXN];pre[l - 1] = suf[r + 1] = -INF;for (int i = l; i <= r; i++)pre[i] = max(pre[i - 1], tmp[i] - i);for (int i = r; i >= l; i--)suf[i] = max(suf[i + 1], tmp[i] + i);int tans = tmp[now];chkmax(tans, pre[now - 1] + r);chkmax(tans, suf[now + 1] - l);if (tans == tmp[now]) {method[++tot] = a[now].home;if (ans[nxtup[now]] == tmp[now]) now = nxtup[now];else if (ans[nxtlup[now]] == tmp[now]) now = nxtlup[now];else if (ans[nxtrup[now]] == tmp[now]) now = nxtrup[now];else now = 0;} else if (tans == pre[now - 1] + r) {for (int i = now; i <= r; i++)method[++tot] = a[i].home;for (int i = now - 1; i >= l; i--) {method[++tot] = a[i].home;if (tans == tmp[i] - i + r) {if (ans[nxtup[i]] == tmp[i]) now = nxtup[i];else if (ans[nxtlup[i]] == tmp[i]) now = nxtlup[i];else if (ans[nxtrup[i]] == tmp[i]) now = nxtrup[i];else now = 0;break;}}} else {for (int i = now; i >= l; i--)method[++tot] = a[i].home;for (int i = now + 1; i <= r; i++) {method[++tot] = a[i].home;if (tans == tmp[i] + i - l) {if (ans[nxtup[i]] == tmp[i]) now = nxtup[i];else if (ans[nxtlup[i]] == tmp[i]) now = nxtlup[i];else if (ans[nxtrup[i]] == tmp[i]) now = nxtrup[i];else now = 0;break;}}}}for (int i = 1; i <= tot; i++)printf("%d ", method[i]);printf("\n");up.clear(), lup.clear(), rup.clear();up[0] = lup[0] = rup[0] = 0;last = n + 1;for (int i = n; i >= 1; i--) {if (a[i].y == a[i - 1].y) continue;int l = i, r = last - 1;for (int j = l; j <= r; j++) {tnp[j] = -INF;if (up.count(a[j].x)) chkmax(tnp[j], up[a[j].x]);if (lup.count(a[j].x + a[j].y)) chkmax(tnp[j], lup[a[j].x + a[j].y]);if (rup.count(a[j].x - a[j].y)) chkmax(tnp[j], rup[a[j].x - a[j].y]);}static int pre[MAXN], suf[MAXN];pre[l - 1] = suf[r + 1] = -INF;for (int j = l; j <= r; j++)pre[j] = max(pre[j - 1], tnp[j]);for (int j = r; j >= l; j--)suf[j] = max(suf[j + 1], tnp[j]);for (int j = l; j <= r; j++) {bns[j] = tnp[j];chkmax(bns[j], pre[j - 1] + j - l);chkmax(bns[j], suf[j + 1] + r - j);bns[j] += 1;up[a[j].x] = bns[j];lup[a[j].x + a[j].y] = bns[j];rup[a[j].x - a[j].y] = bns[j];}last = i;}s = n + 1, t = n + 2;olds = n + 3, oldt = n + 4;for (int i = 0; i <= n; i++) {int nxt = nxtup[i];if (ans[nxt] + bns[i] == ansval) addedge(a[i].home, a[nxt].home);nxt = nxtlup[i];if (ans[nxt] + bns[i] == ansval) addedge(a[i].home, a[nxt].home);nxt = nxtrup[i];if (ans[nxt] + bns[i] == ansval) addedge(a[i].home, a[nxt].home);}for (int i = 0; i <= n; i++) {addedge(olds, i, INF);addedge(i, oldt, INF);}while (bfs()) {memset(curr, 0, sizeof(curr));dinic(s, INF);}addedge(oldt, olds, INF);int finalans = 0;while (bfs()) {memset(curr, 0, sizeof(curr));finalans += dinic(s, INF);}writeln(finalans);return 0;
}

【BZOJ4200】【UOJ132】【NOI2015】小园丁与老司机相关推荐

  1. P2304 [NOI2015] 小园丁与老司机(网络流/上下界网络流)

    P2304 [NOI2015] 小园丁与老司机 平面上有n个点,每次可以向左.右.上.左上45度.右上45度移动,然后直线移动到达第一个没有到过的点,如果没有这样的点就不能移动,求解一条最长路,然后求 ...

  2. BZOJ4200 洛谷2304 UOJ132:[NOI2015]小园丁与老司机——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4200 https://www.luogu.org/problemnew/show/P2304 ht ...

  3. 提高千倍效率的35个编码小技巧,老司机带你飞!

    点击关注公众号,实用技术文章及时了解 来源:henleylee.github.io/posts/2019/a780fcc1.html 前言 代码优化 ,一个很重要的课题.可能有些人觉得没用,一些细小的 ...

  4. mysql入门到跑路_Mysql入门二十小题(DBA老司机带你删库到跑路)2018.11.26

    1. 请介绍数据库管理系统的种类及代表产品 RDBMS: mysql oracle mssql NoSQL: redis  mongoab  memcache 2. 请简述数据库管理系统的作用 数据存 ...

  5. oracle从删库到跑路,Mysql入门二十小题(DBA老司机带你删库到跑路)2018.11.26

    1. 请介绍数据库管理系统的种类及代表产品 RDBMS: mysql oracle mssql NoSQL: redis  mongoab  memcache 2. 请简述数据库管理系统的作用 数据存 ...

  6. 年薪30W的软件测试“老司机”工作经验

    这几天,新入职的小MM提议"老司机"们把自己这些年的软件测试工作经验跟大家分享一下,让新同学学习学习,利用空闲时间我整理了一些,可能不全,勉强看看,这也算是对自己这些年的工作总结. ...

  7. 【新梦想学员干货】必看!年薪30W的软件测试“老司机”工作经验。

    这几天,新入职的小MM提议"老司机"们把自己这些年的软件测试工作经验跟大家分享一下,让新同学学习学习,利用空闲时间我整理了一些,可能不全,勉强看看,这也算是对自己这些年的工作总结. ...

  8. 名悦集团:开车从不追尾,老司机分享驾驶避免事故小知识

    听交通广播,我们几乎每天都能听到高速路上,高架桥上,上班路上发生追尾事故,有时候是个平常的上下班高峰期.很多人会纳闷,车开的好好的,怎么就会发生追尾事故呢.开车在路上,难免会有磕磕碰碰.道路千万条,安 ...

  9. 老司机都在用的浏览器,体积小功能齐全,直呼内行

    现在市面上的浏览器简直是多不胜数,虽然数量多,但是好用的并不多.尤其是某些大厂的浏览器,无用的功能越来越多,越来越臃肿,体积也越来越大,使用体验还不好,有时候甚至不如一些小众浏览器.今天给大家安利2款 ...

  10. 视频教程-老司机讲前端之微信小程序开发成语消消乐游戏视频课程-微信开发

    老司机讲前端之微信小程序开发成语消消乐游戏视频课程 中国实战派HTML5培训第一人,微软技术讲师,曾任百合网技术总监,博看文思HTML5总监.陶国荣长期致力于HTML5.JavaScript.CSS3 ...

最新文章

  1. 「五大常用算法」一文图解分治算法和思想
  2. IDEA svn 更换项目,拉新项目的时候 提示 No appropriate protocol
  3. pageSet还没完count就执行了
  4. [COCI 2017-2018-2]-San
  5. 【渝粤教育】电大中专电大中专职业健康与安全考试考核试题作业 题库
  6. 为什么安装了cmpp没法拖到工具栏_软件SU:简介、安装以及设置
  7. 训练时发生的错误:Couldn‘t open shared file mapping: <000001910A228862>, error code: <1455>
  8. 数字通信系统的主要性能指标
  9. Android Bitmap(位图)详解
  10. Hibernate的批量处理-批量更新
  11. java处理dealfilter_Java-DealString工具类
  12. django filter查询多选_Django重置密码漏洞(CVE201919844)复现和分析
  13. 802.11-2020协议学习__$12-Security__$12.3.2-WEP__1
  14. GOF23式——Prototype
  15. eclipse中输出时出现中文乱码的问题
  16. 搭建自己的NAS 系统
  17. 变形金刚2幕后制作解密
  18. lua 阿拉伯数字转大写(一)
  19. 快餐店收银系统Pos学习笔记
  20. linux和windows双系统传文件夹,如何linux和windows双系统互拷文件?

热门文章

  1. 全球及中国SxS(遥控潜水器)行业商业模式分析及投资风险预测2022年版
  2. OI生涯回忆录(Part8:至高一省选Day1)
  3. java毕业设计演唱会门票订售及管理系统Mybatis+系统+数据库+调试部署
  4. Thinkpad E430 移除网卡白名单
  5. 青出于蓝而胜于蓝 论AI大公司是拼不过小创企的
  6. linux内核vga参数,LINUX grub 修改VGA参数
  7. 服务器系统https打不开网页,记录一次解决网站突然无法打开处理HTTP被封的问题...
  8. 要重复多少次变成潜意识_从骨子里的改变-潜意识的力量!
  9. 柯林斯第八版高阶字典前缀
  10. DDoS攻击--CC攻击防护详解(HTTP)