[Luogu P3645] [BZOJ 4070] [APIO2015]雅加达的摩天楼

10 篇文章 0 订阅
洛谷传送门
BZOJ传送门

题目描述

印尼首都雅加达市有 N N 座摩天楼,它们排列成一条直线,我们从左到右依次将它们编号为 0 N1 N − 1 。除了这 N N 座摩天楼外,雅加达市没有其他摩天楼。

M 只叫做 “doge” 的神秘生物在雅加达市居住,它们的编号依次是 0 0 M1。编号为 i i 的 doge 最初居住于编号为 Bi 的摩天楼。每只 doge 都有一种神秘的力量,使它们能够在摩天楼之间跳跃,编号为 i i 的 doge 的跳跃能力为 Pi Pi>0 P i > 0 )。

在一次跳跃中,位于摩天楼 b b 而跳跃能力为 p 的 doge 可以跳跃到编号为 bp b − p (如果 0bp<N 0 ≤ b − p < N )或 b+p b + p (如果 0b+p<N 0 ≤ b + p < N )的摩天楼。

编号为 0 0 的 doge 是所有 doge 的首领,它有一条紧急的消息要尽快传送给编号为 1 的 doge。任何一个收到消息的 doge 有以下两个选择:

  • 跳跃到其他摩天楼上;
  • 将消息传递给它当前所在的摩天楼上的其他 doge。

请帮助 doge 们计算将消息从 0 0 号 doge 传递到 1 号 doge 所需要的最少总跳跃步数,或者告诉它们消息永远不可能传递到 1 1 号 doge。

输入输出格式

输入格式:

输入的第一行包含两个整数 N M M

接下来 M 行,每行包含两个整数 Bi B i Pi P i

输出格式:

输出一行,表示所需要的最少步数。如果消息永远无法传递到 1 1 号 doge,输出 1

输入输出样例

输入样例#1:
5 3
0 2
1 1
4 1
输出样例#1:
5

说明

【样例解释】

下面是一种步数为 5 5 的解决方案:

0 号 doge 跳跃到 2 2 号摩天楼,再跳跃到 4 号摩天楼( 2 2 步)。

0 号 doge 将消息传递给 2 2 号 doge。

2 号 doge 跳跃到 3 3 号摩天楼,接着跳跃到 2 号摩天楼,再跳跃到 1 1 号摩天楼(3 步)。

2 2 号 doge 将消息传递给 1 号 doge。

【数据范围】

所有数据都保证 0Bi<N 0 ≤ B i < N

子任务 1 (10 分)

1N10 1 ≤ N ≤ 10

1Pi10 1 ≤ P i ≤ 10

2M3 2 ≤ M ≤ 3

子任务 2 (12 分)

1N100 1 ≤ N ≤ 100

1Pi100 1 ≤ P i ≤ 100

2M2000 2 ≤ M ≤ 2000

子任务 3 (14 分)

1N2000 1 ≤ N ≤ 2000

1Pi2000 1 ≤ P i ≤ 2000

2M2000 2 ≤ M ≤ 2000

子任务 4 (21 分)

1N2000 1 ≤ N ≤ 2000

1Pi2000 1 ≤ P i ≤ 2000

2M30000 2 ≤ M ≤ 30000

子任务 5 (43 分)

1N30000 1 ≤ N ≤ 30000

1Pi30000 1 ≤ P i ≤ 30000

2M30000 2 ≤ M ≤ 30000

解题分析

首先我们可以暴力最短路, 但显然这样会卡成 O(NM) O ( N M ) 过不去。

如果只有 PiN P i ≥ N 的情况还好, 我们可以暴力建 NN N N 条边, 勉强卡的过。

Pi<N P i < N 的情况怎么办? 直接暴力预处理即可, 复杂度同样是 O(NN) O ( N N ) 。搞出 N N 层, 每层 N N 个点, 然后暴力连边。 第i层表示 P=i P = i 的情况, 间距为 i i 的点互相连长度为1的边。 再把这些辅助点全部向第 0 0 层(表示原来的点)连长度为0的边。

这样当PiN的时候直接在第 0 0 层暴力连就好。

总复杂度O(αNN)

代码如下:

#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());
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值