• 传送门
  • 思路
  • 正解
  • 参考代码
  • Update
传送门
思路

  唉,我太弱了,我都看出来要分块了,就是做不来。不过终于把题读对了。

  先来看子任务三怎么做。显然可以有一个 O(m2) O ( m 2 ) O(m^2) 的连边,然后直接跑最短路就可以了。但是分好少啊 QAQ,所以我们来看子任务四。我们将在同一个位置的 doge 构成一个零环,然后只向不在同一个位置的 doge 连边,且对于每个位置最多只连接一次边。这样的时间复杂度就是 O(nm) O ( n m ) O(nm) 的了。

  注意,连边只能是 doge 连 doge,不能在位置上跳着跳着连。例如,如果非要把位置作为结点,则只能连 1→3 1 → 3 1 \to 3, 1→5 1 → 5 1 \to 5(注意还要加上边权),不能连两条边权为 1 1 1 的 1→3" role="presentation" style="position: relative;">1→31→31 \to 3, 3→5 3 → 5 3 \to 5。(想一想,为什么)

正解

  我们可以拆点。我们令位置为结点,对于每个位置,我们把它拆成 k+1 k + 1 k + 1 个结点,其中 k k k 为参数。对于被拆的点,我们从 0" role="presentation" style="position: relative;">000 开始编号, 0 0 0 号点表示位置本身,i(i>0)" role="presentation" style="position: relative;">i(i>0)i(i>0)i \pod {i > 0} 号点表示“ i i i 步快速通道”,即向左右的 i" role="presentation" style="position: relative;">iii 步快速通道连一条边权为 1 1 1 的边。

  如上图,如果某个位置有一个跳跃能力为 k" role="presentation" style="position: relative;">kkk 的 doge,我们就从那个位置的 0 0 0 号点向 k" role="presentation" style="position: relative;">kkk 步快速通道连一条边权为 0 0 0 的有向边。另外,我们要保证能够从快速通道回到原结点,所以所有快速通道都要向原结点连一条边权为 0" role="presentation" style="position: relative;">000 的有向边。

  其实,这个做法与其叫拆点,不如叫拆边:

边太多了,真难受

这下好多了(雾)

  显然这么做会有 O(nk) O ( n k ) O(nk) 个结点,多出 O(nk) O ( n k ) O(nk) 条边,因此 k k k 不能太大,也不能太小。对于跳跃能力小于 k" role="presentation" style="position: relative;">kkk 的情况,我们选择建立快速通道,额外时间复杂度为 O(1) O ( 1 ) O(1);对于剩下的我们暴力建边,额外时间复杂度 O(nk) O ( n k ) O(\frac {n} {k})。我们不妨令 nk=nm2k n k = n m 2 k nk = \frac {n \frac {m} {2}} {k},解得 k=m2−−√ k = m 2 k = \sqrt \frac {m} {2},即理论上让 k=120 k = 120 k = 120 左右就好了,实际上由于每只 doge 跳跃能力的不确定(我这里假设两种情况五五开), k k k 到底等于多少才好需要调参。

参考代码

  由于边数很多,所以我们直接判断就好了,无需手动建图。

  另外,上面的参数已经能够满足要求了。调成 m4" role="presentation" style="position: relative;">m4−−√m4\sqrt \frac {m} {4} 更快。

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <cassert>
#include <cctype>
#include <climits>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <set>
#include <bitset>
#include <list>
#include <functional>
typedef long long LL;
typedef unsigned long long ULL;
using std::cin;
using std::cout;
using std::endl;
typedef int INT_PUT;
INT_PUT readIn()
{INT_PUT a = 0; bool positive = true;char ch = getchar();while (!(ch == '-' || std::isdigit(ch))) ch = getchar();if (ch == '-') { positive = false; ch = getchar(); }while (std::isdigit(ch)) { a = a * 10 - (ch - '0'); ch = getchar(); }return positive ? -a : a;
}
void printOut(INT_PUT x)
{char buffer[20]; int length = 0;if (x < 0) putchar('-'); else x = -x;do buffer[length++] = -(x % 10) + '0'; while (x /= 10);do putchar(buffer[--length]); while (length);
}int INF;
const int maxn = 30005;
int n, m;#define RunInstance(x) delete new x
struct work
{static const int maxk = 90;int k;std::vector<std::vector<int> > appear;std::vector<std::vector<int> > fast;std::vector<std::vector<int> > slow;int pos[maxn];int val[maxn];static const int size = maxn * maxk;int dis[size];bool inQ[size];int q[size];int head, tail;void slack(int from, int to, int cost){if (dis[from] + cost < dis[to]){dis[to] = dis[from] + cost;if (!inQ[to]){q[tail] = to;tail = tail + 1 == size ? 0 : tail + 1;inQ[to] = true;}}}void SPFA(){head = tail = 0;memset(dis, 0x3f, sizeof(dis));memset(inQ, 0, sizeof(inQ));dis[pos[0]] = 0;q[tail++] = pos[0];inQ[pos[0]] = true;while (head != tail){int from = q[head];inQ[from] = false;head = head + 1 == size ? 0 : head + 1;if (from >= n){int way = from / n;int idx = from - way * n;int to;if (idx - way >= 0)slack(from, from - way, 1);if (idx + way < n)slack(from, from + way, 1);slack(from, idx, 0);}else{for (int i = 0; i < fast[from].size(); i++)slack(from, from + n * fast[from][i], 0);for (int i = 0; i < slow[from].size(); i++){register int cnt;register int step = slow[from][i];register int cost;cnt = from - step;cost = 1;while (cnt >= 0){slack(from, cnt, cost);cnt -= step;cost++;}cnt = from + step;cost = 1;while (cnt < n){slack(from, cnt, cost);cnt += step;cost++;}}}}}work() : dis(), inQ(){k = std::sqrt(m / 4);appear.resize(n);fast.resize(n);slow.resize(n);for (int i = 0; i < m; i++){pos[i] = readIn();val[i] = readIn();appear[pos[i]].push_back(i);if (val[i] <= k) fast[pos[i]].push_back(val[i]);else slow[pos[i]].push_back(val[i]);}for (int i = 0; i < n; i++){std::sort(fast[i].begin(), fast[i].end());fast[i].resize(std::unique(fast[i].begin(), fast[i].end()) - fast[i].begin());std::sort(slow[i].begin(), slow[i].end());slow[i].resize(std::unique(slow[i].begin(), slow[i].end()) - slow[i].begin());}SPFA();if (dis[pos[1]] >= INF)printOut(-1);elseprintOut(dis[pos[1]]);}
};void run()
{memset(&INF, 0x3f, sizeof(INF));n = readIn();m = readIn();RunInstance(work);
}int main()
{run();return 0;
}
Update

  好像这是个 01 BFS……你懂的……

Luogu 3645 [APIO 2015] 雅加达的摩天楼相关推荐

  1. [APIO 2015] 雅加达的摩天楼

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=4070 [算法] 考虑将每个"Doge"向其所能到达的楼连边 直接 ...

  2. [AOIP 2015] 雅加达的摩天楼

    题目描述: qwq- 题目分析: 其实就是个最短路啊,然后发现建的边最多会有 N2 N 2 N^2条- 所以我们考虑用分块的思想来优化建图. Pi>sqrt(n),暴力加入每一条边,每次最多sq ...

  3. 解题:APIO 2015 雅加达的摩天大楼

    题面 分块思想+最短路 发现对于步长小的doge会连出很多边,很容易导致大量的重边,于是对doge们根据步长分块讨论:根据步长建出分层图,然后把步长不超过某个值的doge们连到对应层上的点上,其余的d ...

  4. 【倍增】【线段树】雨林跳跃(luogu 7599[APIO 2021 T2])

    正题 luogu 7599[APIO 2021 T2] 题目大意 给你一排树中每棵树的高度,每次跳跃可以跳到左/右边第一棵比该树高的树,问你从A-B中某棵树跳到C-D中的某棵树的最小步数(A⩽B< ...

  5. 【堆】【DP】Niyaz and Small Degrees(luogu 7600[APIO 2021 T3]/luogu-CF1119F)

    正题 luogu 7600[APIO 2021 T3] luogu-CF1119F 题目大意 给你一棵树,给出每条边割掉的代价,问你对于0⩽k<n0\leqslant k<n0⩽k< ...

  6. 4070: [Apio2015]雅加达的摩天楼

    4070: [Apio2015]雅加达的摩天楼 Time Limit: 10 Sec   Memory Limit: 256 MB Submit: 415   Solved: 146 [ Submit ...

  7. 题解 P3645 【[APIO2015]雅加达的摩天楼】

    题解 P3645 [[APIO2015]雅加达的摩天楼] 一看求最短先想dp,发现要考虑的状态和转移太多没法做. 再一看是从一个点往另一个点跳,可以考虑最短路. 直接建边会O(n^2) 优化:本题中, ...

  8. bzoj4070【APIO2015】雅加达的摩天楼

    4070: [Apio2015]雅加达的摩天楼 Time Limit: 10 Sec   Memory Limit: 256 MB Submit: 189   Solved: 70 [ Submit] ...

  9. 【BZOJ 4070】 [Apio2015]雅加达的摩天楼

    4070: [Apio2015]雅加达的摩天楼 Time limit: 1000 ms Memory limit: 262144 KB Description The city of Jakarta ...

最新文章

  1. 某厂:有微服务经验者优先!
  2. Linux 系统上的库文件生成与使用
  3. 中国科学技术大学研究生基因组学考试复习提要
  4. POJ 3686 The Windy's
  5. LOJ#2127「HAOI2015」按位或
  6. 蓝牙stack bluez学习(1)Stack Architecture
  7. Spring AOP(一):概览
  8. Neo4j:收集多个值
  9. ios 请求失败封装_vue_axios请求封装、异常拦截统一处理
  10. linux下scrapy安装教程,linux centos7安装scrapy
  11. js文件的断点调试(chrome)
  12. NLP领域首个国家杰青,回归母校!
  13. IE9 下 Flash 显示列表中没有对象后不再显示的Bug
  14. 如何将png图像转换成jpg格式呢?
  15. 手机QQ浏览器的HTML管理器,手机qq浏览器中文件管理器有哪些功能
  16. 暗影精灵7安装Ubuntu双系统、RTX3060 Nvidia 驱动及搭建深度学习环境
  17. SmokePing安装手册
  18. 鸿蒙kal内核,鸿蒙OS发布!官方打脸安卓换壳:华为自研Open鸿蒙内核不兼容安卓...
  19. android拷贝设备断连接,android – Firebase Messaging Inactivity,断开与AppMeasurementService的连接[复制]...
  20. sketch如何做设计稿交互_Sketch交互设计入门到精通教程

热门文章

  1. FPGA-Verilog代码编写及项目设计总结
  2. c语言编译笛卡尔叶形线,全国计算机等级考试C语言2级笔试题-(25)2007年4月1
  3. Java企业级开发框架(三):changelog——0.3.0-SNAPSHOT
  4. 买笔记本,第一是质量
  5. 解决:unable to connect to X server
  6. 深度解读:公有云与私有云有哪些区别?
  7. nexus最全使用教程
  8. Jupyterhub安装配置及心得
  9. 联想等7家企业遭美“337调查”
  10. VMware vSphere vCenter 安装部署(VCSA 6.7)