题目描述:
qwq…
题目分析:
其实就是个最短路啊,然后发现建的边最多会有
条…
所以我们考虑用分块的思想来优化建图。
Pi>sqrt(n),暴力加入每一条边,每次最多sqrt(n)条边。
Pi≤sqrt(n),对于每个点添加sqrt(n)个辅助点,这里可以理解成一栋楼有许多层,每一层一步能走的范围都不同,然后每一层分别连边,每一层到楼底连边。对于一只doge,从楼底到Pi对应的楼层连边。边数是O(n*sqrt(n))的。
跑一下SPFA就可以了…
题目链接:
Ac 代码:
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <queue>
#include <cmath>
#include <cstring>
const int maxm=30005*800;
int cnt;
int n,m,block;
int head[maxm],net[maxm],cost[maxm],to[maxm];
int dis[maxm],vis[maxm];
std::queue <int> dl;
inline void addedge(int u,int v,int c)
{
cnt++;
to[cnt]=v,cost[cnt]=c,net[cnt]=head[u],head[u]=cnt;
}
inline int SPFA(int s,int t)
{
memset(dis,127/3,sizeof(dis));
dl.push(s),vis[s]=1;
dis[s]=0;
while(!dl.empty())
{
int now=dl.front();
dl.pop();
vis[now]=0;
for(int i=head[now];i;i=net[i])
if(dis[to[i]]>dis[now]+cost[i])
{
dis[to[i]]=dis[now]+cost[i];
if(!vis[to[i]]) vis[to[i]]=1,dl.push(to[i]);
}
}
return dis[t]==dis[0]?-1:dis[t];
}
int main()
{
scanf("%d%d",&n,&m);
block=std::min((int)std::sqrt(n),100);
for(int i=1;i<=block;i++)
for(int j=1;j<=n;j++)
{
addedge(i*n+j,j,0);
if(j+i<=n) addedge(i*n+j,i*n+j+i,1),addedge(i*n+j+i,i*n+j,1);
}
int s,t;
for(int i=1;i<=m;i++)
{
int b,p;
scanf("%d%d",&b,&p);
b++;
if(i==1) s=b;
if(i==2) t=b;
if(p>block)
{
for(int j=1;b+j*p<=n;j++) addedge(b,b+j*p,j);
for(int j=1;b-j*p>=1;j++) addedge(b,b-j*p,j);
}
else addedge(b,b+p*n,0);
}
printf("%d\n",SPFA(s,t));
return 0;
}