洛谷传送门
BZOJ传送门
题目描述
印尼首都雅加达市有 N N 座摩天楼,它们排列成一条直线,我们从左到右依次将它们编号为 到 N−1 N − 1 。除了这 N N 座摩天楼外,雅加达市没有其他摩天楼。
有 只叫做 “doge” 的神秘生物在雅加达市居住,它们的编号依次是 0 0 到 。编号为 i i 的 doge 最初居住于编号为 的摩天楼。每只 doge 都有一种神秘的力量,使它们能够在摩天楼之间跳跃,编号为 i i 的 doge 的跳跃能力为 ( Pi>0 P i > 0 )。
在一次跳跃中,位于摩天楼 b b 而跳跃能力为 的 doge 可以跳跃到编号为 b−p b − p (如果 0≤b−p<N 0 ≤ b − p < N )或 b+p b + p (如果 0≤b+p<N 0 ≤ b + p < N )的摩天楼。
编号为 0 0 的 doge 是所有 doge 的首领,它有一条紧急的消息要尽快传送给编号为 的 doge。任何一个收到消息的 doge 有以下两个选择:
- 跳跃到其他摩天楼上;
- 将消息传递给它当前所在的摩天楼上的其他 doge。
请帮助 doge 们计算将消息从 0 0 号 doge 传递到 号 doge 所需要的最少总跳跃步数,或者告诉它们消息永远不可能传递到 1 1 号 doge。
输入输出格式
输入格式:
输入的第一行包含两个整数 和 M M 。
接下来 行,每行包含两个整数 Bi B i 和 Pi P i 。
输出格式:
输出一行,表示所需要的最少步数。如果消息永远无法传递到 1 1 号 doge,输出 。
输入输出样例
输入样例#1:
5 3
0 2
1 1
4 1
输出样例#1:
5
说明
【样例解释】
下面是一种步数为 5 5 的解决方案:
号 doge 跳跃到 2 2 号摩天楼,再跳跃到 号摩天楼( 2 2 步)。
号 doge 将消息传递给 2 2 号 doge。
号 doge 跳跃到 3 3 号摩天楼,接着跳跃到 号摩天楼,再跳跃到 1 1 号摩天楼( 步)。
2 2 号 doge 将消息传递给 号 doge。
【数据范围】
所有数据都保证 0≤Bi<N 0 ≤ B i < N 。
子任务 1 (10 分)
1≤N≤10 1 ≤ N ≤ 10
1≤Pi≤10 1 ≤ P i ≤ 10
2≤M≤3 2 ≤ M ≤ 3
子任务 2 (12 分)
1≤N≤100 1 ≤ N ≤ 100
1≤Pi≤100 1 ≤ P i ≤ 100
2≤M≤2000 2 ≤ M ≤ 2000
子任务 3 (14 分)
1≤N≤2000 1 ≤ N ≤ 2000
1≤Pi≤2000 1 ≤ P i ≤ 2000
2≤M≤2000 2 ≤ M ≤ 2000
子任务 4 (21 分)
1≤N≤2000 1 ≤ N ≤ 2000
1≤Pi≤2000 1 ≤ P i ≤ 2000
2≤M≤30000 2 ≤ M ≤ 30000
子任务 5 (43 分)
1≤N≤30000 1 ≤ N ≤ 30000
1≤Pi≤30000 1 ≤ P i ≤ 30000
2≤M≤30000 2 ≤ M ≤ 30000
解题分析
首先我们可以暴力最短路, 但显然这样会卡成 O(NM) O ( N M ) 过不去。
如果只有 Pi≥N−−√ P i ≥ N 的情况还好, 我们可以暴力建 NN−−√ N N 条边, 勉强卡的过。
但 Pi<N−−√ P i < N 的情况怎么办? 直接暴力预处理即可, 复杂度同样是 O(NN−−√) O ( N N ) 。搞出 N−−√ N 层, 每层 N N 个点, 然后暴力连边。 第层表示 P=i P = i 的情况, 间距为 i i 的点互相连长度为的边。 再把这些辅助点全部向第 0 0 层(表示原来的点)连长度为0的边。
这样当的时候直接在第 0 0 层暴力连就好。
总复杂度。
代码如下:
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#define R register
#define IN inline
#define gc getchar()
#define W while
#define MX 30050
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
int s, t;
int head[MX * 103], dis[MX * 103];
bool vis[MX * 103];
struct Edge {int to, len, nex;} edge[MX * 605];
int dot, cnt, num, layer;
IN int get(R int x, R int y) {return x * dot + y;}
IN void add(R int from, R int to, R int len)
{edge[++cnt] = {to, len, head[from]}, head[from] = cnt;}
std::queue <int> q;
int SPFA()
{
q.push(s); R int i, now;
std::memset(dis, 63, sizeof(dis)); dis[s] = 0;
W (!q.empty())
{
now = q.front(); q.pop();
for (i = head[now]; i; i = edge[i].nex)
{
if(dis[edge[i].to] > dis[now] + edge[i].len)
{
dis[edge[i].to] = dis[now] + edge[i].len;
if(!vis[edge[i].to]) vis[edge[i].to] = true, q.push(edge[i].to);
}
}
vis[now] = false;
}
return dis[t] == dis[0] ? -1 : dis[t];
}
int main(void)
{
int bd, a, b;
in(dot), in(num);
layer = std::min((int)sqrt(dot) + 1, 100);
for (R int i = 1; i <= layer; ++i)
for (R int j = 1; j <= dot; ++j) add(get(i, j), j, 0);
for (R int i = 1; i <= layer; ++i)
{
bd = dot - i;
for (R int j = 1; j <= bd; ++j)
add(get(i, j), get(i, j + i), 1), add(get(i, j + i), get(i, j), 1);
}
for (R int k = 1; k <= num; ++k)
{
in(a), in(b), ++a;
if(k == 1) s = a;
if(k == 2) t = a;
if(b <= layer) add(a, get(b, a), 0);
else
{
for (R int j = 1; a + b * j <= dot; ++j) add(a, a + b * j, j);
for (R int j = 1; a - b * j > 0; ++j) add(a, a - b * j, j);
}
}
printf("%d", SPFA());
}