bzoj4070【APIO2015】雅加达的摩天楼

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

Time Limit: 10 Sec  Memory Limit: 256 MB

Submit: 189  Solved: 70

[Submit][Status][Discuss]

Description

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

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

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

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

跳跃到其他摩天楼上;

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

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

Input

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

接下来 M 行,每行包含两个整数 Bi 和 Pi。

Output

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

Sample Input

5 3

0 2

1 1

4 1

Sample Output

5

explanation

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

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

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

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

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

HINT

子任务

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

子任务 1 (10 分)

1≤N≤10

1≤Pi≤10

2≤M≤3

子任务 2 (12 分)

1≤N≤100

1≤Pi≤100

2≤M≤2000

子任务 3 (14 分)

1≤N≤2000

1≤Pi≤2000

2≤M≤2000

子任务 4 (21 分)

1≤N≤2000

1≤Pi≤2000

2≤M≤30000

子任务 5 (43 分)

1≤N≤30000

1≤Pi≤30000

2≤M≤30000

分块思想+SPFA+建图优化

看到题目第一眼肯定会想到最短路,但最坏情况有n^2条边,显然任何一种最短路算法都不能过。

所以我们考虑用分块的思想来优化建图。

  1. Pi>sqrt(n),暴力加入每一条边,每次最多sqrt(n)条边。
  2. Pi≤sqrt(n),对于每个点添加sqrt(n)个辅助点,这里可以理解成一栋楼有许多层,每一层一步能走的范围都不同,然后每一层分别连边,每一层到楼底连边。对于一只doge,从楼底到Pi对应的楼层连边。边数是O(n*sqrt(n))的。

综上,总边数和总点数都是O(n*sqrt(n))。

然而这道题还卡内存,所以要用到一个小trick:将块的大小和100取min。至于为什么我也不知道,反正这就对了。

分块思想太机智!!!

#include<iostream>
#include<cstdlib>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define maxn 30005*105
#define maxm 30005*500
#define inf 1000000000
using namespace std;
int n,m,s,t,tot,tmp;
int b[30005],p[30005],head[maxn],dis[maxn];
bool inq[maxn];
struct edge_type{int next,to,v;}e[maxm];
queue<int> q;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void add_edge(int x,int y,int v)
{
	e[++tot]=(edge_type){head[x],y,v};head[x]=tot;
}
inline void spfa()
{
	memset(dis,-1,sizeof(dis));
	dis[s]=0;q.push(s);inq[s]=true;
	while (!q.empty())
	{
		int x=q.front();q.pop();inq[x]=false;
		for(int i=head[x];i;i=e[i].next)
		{
			int y=e[i].to;
			if (dis[y]==-1||dis[y]>dis[x]+e[i].v)
			{
				dis[y]=dis[x]+e[i].v;
				if (!inq[y]) q.push(y),inq[y]=true;
			}
		}
	}
}
inline int num(int x,int y)
{
	return x*n+y;
}
int main()
{
	n=read();m=read();
	F(i,1,m) b[i]=read()+1,p[i]=read();
	s=b[1];t=b[2];
	tmp=min((int)sqrt(n),100);
	F(i,1,tmp) F(j,1,n) add_edge(num(i,j),j,0);
	F(i,1,tmp) F(j,1,n-i) add_edge(num(i,j),num(i,j+i),1),add_edge(num(i,j+i),num(i,j),1);
	F(i,1,m)
	{
		if (p[i]<=tmp) add_edge(b[i],num(p[i],b[i]),0);
		else
		{
			for(int j=1;b[i]+j*p[i]<=n;j++) add_edge(b[i],b[i]+j*p[i],j);
			for(int j=1;b[i]-j*p[i]>=1;j++) add_edge(b[i],b[i]-j*p[i],j);
		}
	}
	spfa();
	printf("%d\n",dis[t]);
	return 0;
}
时间: 2024-11-09 04:07:21

bzoj4070【APIO2015】雅加达的摩天楼的相关文章

BZOJ4070: [Apio2015]雅加达的摩天楼

思路{ 对于一条楼上的每一条狗.最直观的方法是把一个点拆成N条狗的点,然后最短路即可. 然而炸空间我也是醉了. 因此我们要用到一个调调的分块优化. 应当是每个点的连通状态.意会一下. 把一座楼分成1-块长层,那对于任意相同层数的狗可以在高空乱JB走. 但连通长度p>块长的呢?------直接连边就可以了. 然后YY一下,处理每条狗的激活关系.SPFA就可以了. } #include<bits/stdc++.h> #define RG register #define il inline

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

4070: [Apio2015]雅加达的摩天楼 Time limit: 1000 ms Memory limit: 262144 KB Description The city of Jakarta has N skyscrapers located on a line, conveniently numbered 0 through N-1 from left to right. There are no other skyscrapers in Jakarta. Jakarta is inh

【题解】P3645 [APIO2015]雅加达的摩天楼(分层图最短路)

[题解]P3645 [APIO2015]雅加达的摩天楼(分层图最短路) 感觉分层图是个很灵活的东西 直接连边的话,边数是$O(n^2)$的过不去 然而我们有一个优化的办法,可以建一个新图$G=(V,E)$其中$V$和原图$V$一一对应且连接一个$0$边,此外每个点向V中的$i+-d$连边. 类似网络流的办法瞎建就行了. 过不了uoj //@winlere #include<iostream> #include<cstdio> #include<cstring> #inc

【bzoj4070】[Apio2015]雅加达的摩天楼 分块+最短路

我们发现每次加入的边模p的余数是相同的,很容易想到对p分块 当p>sqrt(n)时,最多会连出O(sqrt(n))条边,直接连边即可 当p<=sqrt(n)时, 把图分成sqrt(n)+1层,最底层表示原来的节点 从下往上依次表示p=1.2.3--时的节点 对于每个p,把模p的余数相同的点顺次连接 对于每个读入的p,从最底层向对应的第p层的节点连一条权值为0的边即可 据说spfa快? 还算是道不错的题 O(3*n*sqrt(n)+2*num*sqrt(n)+(m-num)) #include&

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

Descrption 有\(m\)只doge,每只doge只能到\(b_i+kp_i,k\in Z\),求0号doge将信息传给1号doge的最少跳跃步数.\(n\leqslant 3\times 10^4\) Solution 分块. 将\(p\)分成大于\(\sqrt n\)和小于等于\(\sqrt n\)的两部分,然后小于的部分可以暴力建好图再连边,大于的部分直接连所有能到达的位置即可. 复杂度\(O(n\sqrt n)\). PS:UOJ上过不了Extra Text... 其实时间复杂度

APIO2015 雅加达的摩天楼

首先可以看出这是一道求最短路的题目,但暴力建图最多n2 条边,所以考虑建图优化 对于p>sqrt(n) 的青蛙可以直接暴力建,最多n*sqrt(n) 条边 对于p<sqrt(n) 的青蛙添加辅助点,枚举这sqrt(n)个长度,每个长度建立n个辅助点前后对应连边,同时向它们可以到达的点以及可以到达它们的点连边 1 #define MAXN 4000010UL 2 #include <cstdio> 3 #include <queue> 4 #include <cma

bzoj 4070: [Apio2015]雅加达的摩天楼【spfa】

明明是个最短路却有网络流一样的神建图= A = 首先要是暴力建图的话最坏有O(nm)条边.所以优化建图. 考虑分块思想,设bs=sqrt(n),对于p大于bs的,直接连边即可,最多有sqrt(n)条,注意边权不全是1了,因为要从b走过去:对于p小于等于bs,先把每栋楼建sqrt个辅助点,然后这些辅助点向原点连边,其中i点的辅助点j表示i栋楼可以跳p步.这些辅助点同层之间连双向边.然后对于一只狗,直接连接b点与b点的第p辅助点即可. spfa即可 然而事实证明bs取sqrt甚至会re,直接取100

UOJ111 APIO2015 雅加达的摩天楼 最短路、根号分治、bitset

传送门 70+Hack数据真是壮观~ 不难考虑到一个暴力的做法:设\(f_{i,j}\)表示在第\(i\)个点.从第\(j\)个doge跳过来的最短距离,因为边权为\(1\)所以就是个BFS,复杂度\(O(NM)\). 注意到可以优化一些状态:设\(f_{i,j}\)表示在第\(i\)个点.当前的doge的步长为\(j\)的方案数,然后再跑BFS. 看似这样还是\(O(N^2)\)的,但是实际复杂度变为了\(O(N\sqrt{N})\),复杂度分析考虑根号分治:当步长\(> \sqrt{N}\)

luogu P3645 [APIO2015]雅加达的摩天楼

luogu 暴力? 暴力! 这个题有点像最短路,所以设\(f_{i,j}\)表示在\(i\)号楼,当前\(doge\)跳跃能力为\(j\)的最短步数,转移要么跳一步到\(f_{i+j,j}\)和\(f_{i-j,j}\),要么换到别的\(doge\),转移到\(f_{i,k}\) 这看似有\(n^2\)的状态,实际上状态数只有\(n\sqrt n\).因为当\(p> \sqrt n\)时,一个\(doge\)只能跳到\(\sqrt n\)个不同的点,这部分为\(m\sqrt n\);当\(p\l