luogu P3645 [APIO2015]雅加达的摩天楼 分块 根号分治
LINK:雅加达的摩天楼
容易想到设\(f_{i,j}\)表示第i个\(doge\)在第j层楼的最小步数.
转移显然是bfs.值得一提的是把初始某层的\(doge\)加入队列 然后转移边权全为1不需要 双端队列的bfs.
复杂度为状态数量\(n\cdot m\)
可以发现 可能有两个\(doge\)跳在同一层楼 且 跳跃能力相同 显然其中一个一定没用 可以进行一些小优化 将状态改写成\(f_{i,j}\)到达第i层楼跳跃能力为j的最小步数.
复杂度\(n\cdot sqrt n\) 证明和另外一种解法如下:
观察\(n\)为\(30000\)容易想到利用分块来解决问题.
把跳跃能力和\(B=\sqrt n\)做比较,可以当跳跃能力\(p_i<=B\)时 将这种能力在图中的边连接 边数最坏为\(n\cdot B\)
当\(p_i>B\)时 最坏可跳位置只有\(\frac{n}{B}\)个 此时边数为\(m\cdot \frac{n}{B}\)即\(m\cdot B\)
可以得到边数的数量级为\(n\cdot B\) 也就是到达某个点的状态\(i,j\)跳跃能力为j这样的二元组只有\(n\cdot B\)个.
设\(f_{i,j}\)表示到达第i层楼此时跳跃能力为j的最小步数。
直接bfs即可 复杂度为状态数\(n\cdot B\)
code
//#include<bits/stdc++.h>
#include<iostream>
#include<queue>
#include<iomanip>
#include<cctype>
#include<cstdio>
#include<deque>
#include<utility>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<cstdlib>
#include<vector>
#include<algorithm>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define INF 1000000000
#define ll long long
#define db double
#define mod 1000000007
#define pii pair<ll,ll>
#define mk make_pair
#define us unsigned
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
int x=0,f=1;char ch=getc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
return x*f;
}
const int MAXN=30010;
int n,m,ans=-1,st,en;
int vis[MAXN];
vector<int>g[MAXN];
bitset<MAXN>w[MAXN];
struct wy
{
int x,p;
int v;
};
queue<wy> q;
inline void insert(int x,int c,int v)
{
if(!w[x][c]){q.push((wy){x,c,v});w[x][c]=1;}
if(vis[x])return;
for(us int i=0;i<g[x].size();++i)
{
int tn=g[x][i];
if(!w[x][tn])
{
q.push((wy){x,tn,v});
w[x][tn]=1;
}
}
vis[x]=1;
}
inline void bfs()
{
while(q.size())
{
wy a=q.front();q.pop();
if(a.x==en){ans=a.v;return;}
if(a.x-a.p>=0)insert(a.x-a.p,a.p,a.v+1);
if(a.x+a.p<n)insert(a.x+a.p,a.p,a.v+1);
}
}
int main()
{
//freopen("1.in","r",stdin);
n=read();m=read();
for(int i=1;i<=m;++i)
{
int x,p;
x=read();p=read();
if(i==1)st=x;
if(i==2)en=x;
g[x].push_back(p);
}
vis[st]=1;
for(us int i=0;i<g[st].size();++i)
{
int tn=g[st][i];
if(!w[st][tn])
{
q.push((wy){st,tn,0});
w[st][tn]=1;
}
}
bfs();
printf("%d\n",ans);
return 0;
}