正题
题目链接:https://www.luogu.com.cn/problem/P3645
题目大意
nnn个点,mmm条狗,第iii条狗可以往左或者右跳恰好pip_ipi步,开始是000号狗,每次跳跃到达一个点可以选择换一条狗,求到111号狗所在点的最短路。
解题思路
为了方便设n,mn,mn,m同级
对于pi≤np_i\leq \sqrt npi≤n的狗,pip_ipi的种类只有n\sqrt nn级别,每条狗能到达的点是O(n)O(n)O(n)级别
对于pi>np_i>\sqrt npi>n的狗,pip_ipi的种类有O(n)O(n)O(n)级别,每条狗能到达的点数是O(n)O(\sqrt n)O(n)级别。
所以总共的状态数不超过O(nn)O(n\sqrt n)O(nn)个,暴力bfsbfsbfs就好了。
对于储存状态可以按照n\sqrt nn为分界用两种不同的方式储存,当然还有更暴力的方法就是直接用bitsetbitsetbitset存。
时间复杂度O(nn)O(n\sqrt n)O(nn)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<bitset>
#include<vector>
#define mp(x,y) make_pair(x,y)
using namespace std;
const int N=3e4+10;
int n,m,S,T;
bitset<N>v[N];
vector<int>s[N];
queue<pair<pair<int,int> ,int> >q;
int bfs(){for(int i=0;i<s[S].size();i++)q.push(mp(mp(S,s[S][i]),0)),v[S][s[S][i]]=1;while(!q.empty()){int x=q.front().first.first,w=q.front().first.second,d=q.front().second;int y=x-w;if(y>=0){if(y==T)return d+1;for(int i=0;i<s[y].size();i++)if(!v[y][s[y][i]])q.push(mp(mp(y,s[y][i]),d+1)),v[y][s[y][i]]=1;if(!v[y][w])q.push(mp(mp(y,w),d+1)),v[y][w]=1;}y=x+w;if(y<n){if(y==T)return d+1;for(int i=0;i<s[y].size();i++)if(!v[y][s[y][i]])q.push(mp(mp(y,s[y][i]),d+1)),v[y][s[y][i]]=1;if(!v[y][w])q.push(mp(mp(y,w),d+1)),v[y][w]=1;}q.pop();}return -1;
}
int main()
{scanf("%d%d",&n,&m);for(int i=0;i<m;i++){int x,w;scanf("%d%d",&x,&w);if(i==0)S=x;if(i==1)T=x;s[x].push_back(w);}if(S==T)return puts("0")&0;printf("%d\n",bfs());return 0;
}