印尼首都雅加達市有 NNN 座摩天樓,它們排列成一條直線,咱們從左到右依次將它們編號爲 000 到 $N − 1$ 。除了這 NNN 座摩天樓外,雅加達市沒有其餘摩天樓。ios
有 MMM 只叫作 「doge」 的神祕生物在雅加達市居住,它們的編號依次是 000 到 $M − 1$ 。編號爲 iii 的 doge 最初居住於編號爲 BiB_iBi 的摩天樓。每隻 doge 都有一種神祕的力量,使它們可以在摩天樓之間跳躍,編號爲 iii 的 doge 的跳躍能力爲 PiP_iPi ( Pi>0P_i > 0Pi>0 )。測試
在一次跳躍中,位於摩天樓 bbb 而跳躍能力爲 ppp 的 doge 能夠跳躍到編號爲 $b − p$ (若是 $0 \leq b − p < N$ )或 b+pb + pb+p (若是 0≤b+p<N0 \leq b + p < N0≤b+p<N )的摩天樓。spa
編號爲 000 的 doge 是全部 doge 的首領,它有一條緊急的消息要儘快傳送給編code
號爲 111 的 doge。任何一個收到消息的 doge 有如下兩個選擇:blog
跳躍到其餘摩天樓上;ci
將消息傳遞給它當前所在的摩天樓上的其餘 doge。get
請幫助 doge 們計算將消息從 000 號 doge 傳遞到 111 號 doge 所須要的最少總跳躍步數,或者告訴它們消息永遠不可能傳遞到 111 號 doge。string
輸入的第一行包含兩個整數 NNN 和 MMM 。it
接下來 MMM 行,每行包含兩個整數 BiB_iBi 和 PiP_iPi 。io
輸出格式:輸出一行,表示所須要的最少步數。若是消息永遠沒法傳遞到 111 號 doge,輸出 $−1$ 。
【樣例解釋】
下面是一種步數爲 555 的解決方案:
000 號 doge 跳躍到 222 號摩天樓,再跳躍到 444 號摩天樓( 222 步)。
000 號 doge 將消息傳遞給 222 號 doge。
222 號 doge 跳躍到 333 號摩天樓,接着跳躍到 222 號摩天樓,再跳躍到 111 號摩天樓( 333 步)。
222 號 doge 將消息傳遞給 111 號 doge。
【數據範圍】
全部數據都保證 $0≤Bi<N0 \leq B_i < N0≤Bi<N $。
子任務 1 (10 分) $1≤N≤101 \leq N \leq 101≤N≤10$
$1≤Pi≤101 \leq P_i \leq 101≤Pi≤10$
$2≤M≤32 \leq M \leq 32≤M≤3$
子任務 2 (12 分)$1≤N≤1001 \leq N \leq 1001≤N≤100$
$1≤Pi≤1001 \leq P_i \leq 1001≤Pi≤100$
$2≤M≤20002 \leq M \leq 20002≤M≤2000$
子任務 3 (14 分) $1≤N≤20001 \leq N \leq 20001≤N≤2000$
$1≤Pi≤20001 \leq P i ≤ 20001≤Pi≤2000$
$2≤M≤20002 \leq M \leq 20002≤M≤2000$
子任務 4 (21 分) $1≤N≤20001 \leq N \leq 20001≤N≤2000$
$1≤Pi≤20001 \leq P_i \leq 20001≤Pi≤2000$
$2≤M≤300002 \leq M \leq 300002≤M≤30000$
子任務 5 (43 分) $1≤N≤300001 \leq N \leq 300001≤N≤30000$
$1≤Pi≤300001 \leq P_i \leq 300001≤Pi≤30000$
$2≤M≤300002 \leq M \leq 300002≤M≤30000$
首先對於一個(i,p),若是暴力建邊,複雜度$O(mn)$
首先考慮分塊
若是p大於$n^{\frac{1}{2}}$那麼直接建邊$O(n^{\frac{1}{2}})$
若是p小於$n^{\frac{1}{2}}$
首先有一個思路就是設vis[i][p]表示是否考慮過(i,p)
這樣就不會重複建邊,邊數最多$m*n^{\frac{1}{2}}*log$
這樣簡單易懂,但空間卻不夠
若是不是捆綁測試就能拿不少分
因而轉化建邊思路,在p小於$n^{\frac{1}{2}}$
每一個點建$n^{\frac{1}{2}}$個輔助點,設爲<i,p>點
事先這樣建邊
1.給每一個<i,p>向$i$連邊,權爲0
2.給每一個<i,p>與<i+p,p>建雙向邊
若是有一個doge是(i,p)的,那麼
$i$連<i,p>,邊權爲0
這樣建邊保證跑最短路時從i跳到i+p,能夠直接從輔助點
並且保證了一個路徑必然是從有doge的地方出發的,否則根本到不了相應的輔助點
這樣邊數保證在$m*n^{\frac{1}{2}}$
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<queue> 7 using namespace std; 8 struct Node 9 { 10 int next,to,dis; 11 }edge[30001*101*5]; 12 int dist[30001*101],lim,S,T,inf,head[30001*101],n,m,num,cnt; 13 bool vis[30001][101]; 14 queue<int>Q; 15 bool viss[30001*101]; 16 int get_id(int x,int y) 17 { 18 return y*n+x; 19 } 20 void add(int u,int v,int dis) 21 { 22 num++; 23 edge[num].next=head[u]; 24 head[u]=num; 25 edge[num].to=v; 26 edge[num].dis=dis; 27 } 28 void SPFA() 29 {int i; 30 memset(dist,127/3,sizeof(dist)); 31 Q.push(S); 32 inf=dist[0]; 33 memset(viss,0,sizeof(viss)); 34 dist[S]=0; 35 while (Q.empty()==0) 36 { 37 int u=Q.front(); 38 Q.pop(); 39 viss[u]=0; 40 for (i=head[u];i;i=edge[i].next) 41 { 42 int v=edge[i].to; 43 if (dist[v]>dist[u]+edge[i].dis) 44 { 45 dist[v]=dist[u]+edge[i].dis; 46 if (viss[v]==0) 47 { 48 viss[v]=1; 49 Q.push(v); 50 } 51 } 52 } 53 } 54 } 55 int main() 56 {int i,b,p,j; 57 cin>>n>>m; 58 lim=min((int)sqrt(n),100); 59 for (i=1;i<=n;i++) 60 for (j=1;j<=lim;j++) 61 add(get_id(i,j),i,0); 62 for (i=1;i<=n;i++) 63 for (j=1;j<=lim;j++) 64 if (i+j<=n) 65 add(get_id(i,j),get_id(i+j,j),1),add(get_id(i+j,j),get_id(i,j),1); 66 for (i=0;i<m;i++) 67 { 68 scanf("%d%d",&b,&p); 69 b++; 70 if (i==0) S=b; 71 if (i==1) T=b; 72 if (p>lim) 73 {cnt=0; 74 for (j=b;j+p<=n;j+=p) 75 { 76 add(b,j+p,++cnt); 77 } 78 cnt=0; 79 for (j=b;j-p>0;j-=p) 80 { 81 add(b,j-p,++cnt); 82 } 83 } 84 else 85 { 86 add(b,get_id(b,p),0); 87 } 88 } 89 SPFA(); 90 if (dist[T]==inf) cout<<-1; 91 else 92 cout<<dist[T]; 93 }