前言

题目链接:洛谷

题意简述

你被困在一个被划分为 \(2500 \times 2500\) 的二维平面内!平面上有 \(n\)(\(n \leq 250000\))个岛屿你可以停留,你可以在这些岛屿之间行走,但是你只能走到严格在当前岛屿的左上或右下的岛屿。即目标点 \((x', y')\) 满足和当前点 \((x, y)\) 的关系为:\((x' < x \land y' < y) \lor (x' > x \land y' > y)\)。问分别从每个岛屿出发,分别走到其他岛屿的最小步数之和是多少。

题目分析

你当然可以暴力建图加分别跑 BFS,时间复杂度 \(\Theta(n ^ 3)\)。优化?难道说扫描线的同时线段树优化建图再然后 01-BFS?似乎这样变得更劣、更难继续优化了?不太行。所以考虑换一个思路。

发现平面边长是 \(2500\),在引导我们思考有关平面边长的平方的算法。

经过玩样例发现,不能直接一步走到的地方是左下角和右上角的一片区域。并且这两片区域会越来越小,直到里面一个岛屿都没有了后停止。

比如从 \((4, 5)\) 出发,用灰色区域表示能够直接一次走到的区域。即从当前 \(k\) 步之内能到达的区域,使用 \(k + 1\) 步能够到达的区域。

然后继续,接下来能够直接一次走到的区域,也即走 \(2\) 步及以内能到达的区域。

发现 \(2\) 步以内就能走到所有岛屿。过程中,没有被灰色覆盖的区域就是所谓的“不能直接一步走到的区域”。这个逐渐减少的过程也很好理解。

那么,状态就可以记这两个区域了。发现两个区域互相独立,所以可以分别计算。并且发现,在计算步数时,每次加上当前不能一次走到的区域的个数就行了,这相当于把某一个区域对答案的贡献拆到了每走一步里。注意初始每个位置至少需要 \(1\) 步,以及不要把起点算进去。这个式子在下面会列出来。

设 \(f[x][y]\) 表示当前不能一次走到的区域是以 \((x, y)\) 为右上角的区域,里面的区域对答案的贡献。同理,\(g[i][j]\) 表示当前不能一次走到的区域是以 \((x, y)\) 为左下角的区域,里面的区域对答案的贡献。

如果起点是 \((x, y)\),上面我们讲的答案就是 \((n - 1) + (f[x][y] - 1) + (g[x][y] - 1)\)。

那该如何转移呢?以左下角的 \(f[x][y]\) 为例。

首先,我们要知道这一片区域内岛屿的数量,二维前缀和即可。其次,我们要知道下一个状态。我们要在这个区域的右边能够到达的区域里,找到最下方的一个岛屿,下一个状态的纵坐标就是这个岛屿的纵坐标。以及在上方能够到达的区域里,找到最左边的一个岛屿,作为下一个状态的横坐标。可以结合上面的样例理解。这个可以用前后缀最值预处理。

实现的时候,用一个记忆化搜索就行了。不知道为什么有题解说要特判 \(n = 1\),不特判也能过。

代码

略去了快写。是最优解

#include <cstdio>
#include <cstring>
using namespace std; int n, x[250010], y[250010];
bool on[2510][2510];
int sum[2510][2510];
int mini[2510], minj[2510];
int maxi[2510], maxj[2510]; inline int min(int a, int b) {
return a < b ? a : b;
} inline int max(int a, int b) {
return a > b ? a : b;
} int ur(int x, int y) {
static int f[2510][2510];
static bool vis[2510][2510];
if (vis[x][y]) return f[x][y];
vis[x][y] = true;
if (sum[x][2500] - sum[x][y - 1] == 0) return 0;
return f[x][y] = sum[x][2500] - sum[x][y - 1] + ur(min(x, mini[y - 1]), max(y, maxj[x + 1]));
} int dl(int x, int y) {
static int f[2510][2510];
static bool vis[2510][2510];
if (vis[x][y]) return f[x][y];
vis[x][y] = true;
if (sum[2500][y] - sum[x - 1][y] == 0) return 0;
return f[x][y] = sum[2500][y] - sum[x - 1][y] + dl(max(x, maxi[y + 1]), min(y, minj[x - 1]));
} signed main() {
fread(buf, 1, MAX, stdin);
read(n);
memset(mini, 0x3f, sizeof mini);
memset(minj, 0x3f, sizeof minj);
for (int i = 1; i <= n; ++i) {
read(x[i]), read(y[i]), on[x[i]][y[i]] = true;
mini[y[i]] = min(mini[y[i]], x[i]);
maxi[y[i]] = max(maxi[y[i]], x[i]);
minj[x[i]] = min(minj[x[i]], y[i]);
maxj[x[i]] = max(maxj[x[i]], y[i]);
}
for (int i = 1; i <= 2500; ++i) {
mini[i] = min(mini[i], mini[i - 1]);
minj[i] = min(minj[i], minj[i - 1]);
}
for (int i = 2500; i; --i) {
maxi[i] = max(maxi[i], maxi[i + 1]);
maxj[i] = max(maxj[i], maxj[i + 1]);
}
for (int i = 1; i <= 2500; ++i)
for (int j = 1; j <= 2500; ++j)
sum[i][j] = on[i][j] + sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1];
for (int i = 1; i <= n; ++i) {
write(n + (ur(x[i], y[i]) - 1) + (dl(x[i], y[i]) - 1) - 1);
putchar('\n');
}
fwrite(obuf, 1, o - obuf, stdout);
return 0;
}

后记 & 反思

对对对,扫描线的同时线段树优化建图再然后 01-BFS 发现无从下手的人就是我。

这道题转化模型、寻找性质,以及拆贡献的方法,对我们有诸多启示。

[CEOI 2013] 千岛之国 / Adritic 题解的更多相关文章

  1. 洛谷 P2482 loj #2885 [SDOI2010]猪国杀 题解【模拟】【贪心】【搜索】

    好玩的模拟题. 以后要经常写模拟题鸭 题目描述 游戏背景 <猪国杀>是一种多猪牌类回合制游戏,一共有\(3\)种角色:主猪,忠猪,反猪.每局游戏主猪有且只有\(1\)只,忠猪和反猪可以有多 ...

  2. 洛谷P2482 [SDOI2010]猪国杀——题解

    猪国杀,模拟题的一颗耀眼的明珠,成长大牛.锻炼码力必写题! 模拟题没什么思维难度.只要按部就班地去做就是.模拟简单在这,难也在这.因为题面巨长,条件巨多,忽疏一点都有可能全盘皆输.故推荐考试时碰见了, ...

  3. Yali 19 - 8 - 6 test T2 猪国(pig) 题解

    T2 猪国 题⽬描述 猪国是⼀个由 \(n\) 个城市组成的国家. 国王意识到了"要致富,先修路"这句话的重要性,它决定⼤规模修路.不巧的是,猪国的 猪们不太会⼯程,于是只能请隔壁 ...

  4. 【2013南京区域赛】部分题解 hdu4802—4812

    上周末打了一场训练赛,题目是13年南京区域赛的 这场题目有好几个本来应该是我擅长的,但是可能是太久没做比赛了各种小错误代码写的也丑各种warusn trush搞得人很不爽 全场题之一的1002也没有想 ...

  5. The 2013 South America/Brazil Regional Contest 题解

    A: UVALive 6525 cid=61196#problem/A" style="color:blue; text-decoration:none">Atta ...

  6. Bzoj1972: [Sdoi2010]猪国杀 题解(大模拟+耐心+细心)

    猪国杀 - 可读版本 https://mubu.com/doc/2707815814591da4 题目可真长,读题都要一个小时. 这道题很多人都说不可做,耗时间,代码量大,于是,本着不做死就不会死的精 ...

  7. 2013年NOIP普及组复赛题解

    题目涉及算法: 计数问题:枚举: 表达式求值:栈: 小朋友的数字:动态规划: 车站分级:最长路. 计数问题 题目链接:https://www.luogu.org/problem/P1980 因为数据量 ...

  8. 【SDOI2010】猪国杀 题解(模拟)

    前言:嗅到了一丝头秃的味道…… ------------------ 题目链接 题目实在太长,变量也很多.建议至少读个三五遍再做题.不要忽略任何细节,不要想当然.(因为真正玩三国杀肯定不像猪一样出牌啊 ...

  9. 【备考06组01号】第四届蓝桥杯JAVA组A组国赛题解

    1.填算式 (1)题目描述     请看下面的算式:     (ABCD - EFGH) * XY = 900     每个字母代表一个0~9的数字,不同字母代表不同数字,首位不能为0.     比如 ...

  10. 【2013杭州区域赛】部分题解 hdu4770—4780

    1008: 题意: 有20W个数,每个数都在20W以内,现在有20W个询问,每次询问L,R区间内不会打架的数有多少个 定义两个数不互质 就会打架 解法: 脑洞很大的一道题,先要进行预处理,对每一个数预 ...

随机推荐

  1. RSS 解析:全球内容分发的利器及使用技巧

    使用 RSS 可以将最新的网络内容从一个网站分发到全球数千个其他网站. RSS 允许快速浏览新闻和更新. RSS 文档示例 <?xml version="1.0" encod ...

  2. 自定义U盘图标

    有没有想过你可以自定义U盘的图标 我才不想用这么Low的图标: 我的图标是这样的: 不好意思,本人叫郭飞,嘻嘻... 下面给出教程: 1.U盘里新建文件autorun.inf,并用记事本打开进行编辑 ...

  3. FFmpeg开发笔记(三十二)利用RTMP协议构建电脑与手机的直播Demo

    不管是传统互联网还是移动互联网,实时数据传输都是刚需,比如以QQ.微信为代表的即时通信工具,能够实时传输文本和图片.其中一对一的图文通信叫做私聊,多对多的图文通信叫做群聊. 除了常见的图文即时通信,还 ...

  4. Linux 内核:设备驱动模型 学习总结

    背景 其实之前就转载过别人针对Linux的设备驱动模型(Linux Device Driver Model,LDDM)的文章,但是受限于自身的能力,因此花了点时间重新学习了一下. 前人写的文章很好,我 ...

  5. 在高通lk中添加自定义源文件

    在高通lk中添加自定义源文件 背景 在lk开发中,需要添加一个自定义功能,但是又不希望代码污染无关的文件(把无关代码添加到某个源文件中是一种罪). 以添加一个aw9523b.c的驱动为例,在aboot ...

  6. 背包DP——多重背包

    多重背包也是 0-1 背包的一个变式.与 0-1 背包的区别在于每种物品有 k 个,而非一个. 朴素 直接把相同的每个物品视作各个单独的物品,没有关联,仅条件相同: 转换后直接用01背包的状态转移方程 ...

  7. MathType选项灰色无法点击或者word无法粘贴,治本解决方案

    问题描述: mathtype安装过后,word中会出现mathtype的选项,但是这时mathtype中的选项是虚的,无法点击,而且此时word无法粘贴内容. 解决步骤: 1.打开word选项,点击加 ...

  8. Netcode for Entities里如何对Ghost进行可见性筛选(1.2.3版本)

    一行代码省流:SystemAPI.GetSingleton() 当你需要按照区域.距离或者场景对Ghost进行筛选的时候,Netcode for Entities里并没有类似FishNet那样方便的过 ...

  9. SparkSQL on K8s 在网易传媒的落地实践

    作者:鲁成祥 易顺 随着云原生技术的发展和成熟,大数据基础设施积极拥抱云原生是业内发展的一大趋势.网易传媒在 2021 年成功将 SparkSQL 部署到了 K8s 集群,并实现与部分在线业务的混合部 ...

  10. webgl未使用独立显卡报告2

    楔子 在上一篇文章 <# [https://juejin.cn/post/7074771064286347301] webgl未使用独立显卡报告> 发表后,有读者在公众号给我发了一段评论, ...