BZOJ 4070:[APIO2015]雅加达的摩天楼 最短路
4070: [Apio2015]雅加达的摩天楼
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 464 Solved: 164
[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
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。
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
Source
想法:因为同一个doge不会再跑回来,所以这样暴力连边:Bi->Bi+k*Pi dis=k;K∈N.O(n^2)
另一个暴力:每种P,对于每种模数[0,P-1]。建一条轨道,轨道之间连双向边边权为1.然后Bi直接连Bi对应的轨道点P,边权为0.O(n^2)
优化第二个暴力:如果这个模数上并没有点那就不用建了。
分析一发复杂度:最坏情况,那肯定是所有轨道上都只有一个点。模数越大,一个点要建的轨道越小:N/P。所以最坏数据P从1开始,每个模数都有一个。
M=1+2+3+...+X。X=sqrt (2*M) 所以共O(sqrt(2*M)*n)条边...理论复杂度过了,但也许需要卡卡空间.....
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<vector> #include<algorithm> #define usint unsigned short int #define next(x) x==M?1:x+1 #define swap(a,b) a^=b,b^=a,a^=b; //1<<16 -1 const int len(30000),N(7333654),INF(0x7fffffff),M(733365); int n,m,now,S,T,last[len+10]; struct Data{usint B,P,k;}doge[len+10]; bool cmp(Data X,Data Y){if(X.P==Y.P)return X.k<Y.k;return X.P<Y.P;} struct Node{int nd,nx;}bot[len+10]; int tot,first[len+10],Down[N+10],Up[N+10];//卡空间 usint To[N+10]; void add(int a,int b){bot[++tot]=(Node){b,first[a]};first[a]=tot;} template <class T>void read(T &x) { x=0; char ch=getchar(); int f=0; while(ch<'0'||ch>'9'){f=(ch=='-');ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} x=f?-x:x; } int q[M+10],l,h,x,y; int dis[N+10]; bool flag[N+10]; void Spfa() { for(int i=0;i<=now;i++)dis[i]=INF;//dis[0]=0; q[l=1]=S; dis[S]=0; h=0; flag[S]=1; while(h!=l) { h=next(h); x=q[h]; y=next(h); if(x<=n) { for(int v=first[x];v;v=bot[v].nx) if(dis[bot[v].nd]>dis[x]) { dis[bot[v].nd]=dis[x]; if(!flag[bot[v].nd]) { l=next(l); q[l]=bot[v].nd; flag[bot[v].nd]=1; if(dis[q[l]]>dis[q[y]])swap(q[y],q[l]); } } }else { if(dis[To[x]]>dis[x]) { dis[To[x]]=dis[x]; if(!flag[To[x]]) { l=next(l); q[l]=To[x]; flag[To[x]]=1; if(dis[q[l]]>dis[q[y]])swap(q[y],q[l]); } } if(dis[Down[x]]>dis[x]+1) { dis[Down[x]]=dis[x]+1; if(!flag[Down[x]]) { l=next(l); q[l]=Down[x]; flag[Down[x]]=1; if(dis[q[l]]>dis[q[y]])swap(q[y],q[l]); } } if(dis[Up[x]]>dis[x]+1) { dis[Up[x]]=dis[x]+1; if(!flag[Up[x]]) { l=next(l); q[l]=Up[x]; flag[Up[x]]=1; if(dis[q[l]]>dis[q[y]])swap(q[y],q[l]); } } } flag[x]=0; } } int main() { read(n),read(m); for(int i=1;i<=m;i++) { read(doge[i].B),read(doge[i].P); doge[i].k=doge[i].B%doge[i].P; } S=doge[1].B;T=doge[2].B; std::sort(doge+1,doge+1+m,cmp); now=n; for(int i=1;i<=m;i++) { if(doge[i].P!=doge[i-1].P || doge[i].k!=doge[i-1].k) for(int j=doge[i].k;j<n;j+=doge[i].P) { To[++now]=j; if(j!=doge[i].k)Down[now]=now-1;else Down[now]=now; if(j+doge[i].P<n)Up[now]=now+1;else Up[now]=now; last[j]=now; } add(doge[i].B,last[doge[i].B]); } Spfa(); printf("%d",dis[T]!=INF?dis[T]:-1); return 0; }