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;
}
posted @ 2020-07-20 17:27  chdy  阅读(149)  评论(0编辑  收藏  举报