Codeforces Round 751 (Div. 2)(D)
Codeforces Round 751 (Div. 2)(D)
D
题目还蛮绕的,看半天才看懂
题目大意就是有一个青蛙,在地下\(n\)处,当它走到\(x\)处,它可以往上走最多\(a_x\)个距离,然后到达了\(y\),然后再休息一下,就是往后走\(b_y\)个距离,最后到达\(z\)
问这个青蛙从\(n\)走到\(0\)的最小往前走的次数,每次往前走到达的位置(还未休息)
然后我当时偷了个懒,去看了标签,看到上面写着是\(dp\),水平不到家,想了半天,还是没想出来,只好去找题解了
看了题解,我感觉更多的像是最短路的求法
只不过我们普通的最短路只会记录一个位置,我们这个需要记录两个位置,\(now\),\(u\),我是这么理解的,我们一开始是到达\(now\)的,但是我们还需要休息,所以就会到达\(u\)
这样我们就可以这道某一步可以走的距离的范围了,是\([1,a[now]]\)
其余的就按照最短路的求法更新\(dis\)
但是我们还需注意对于从后往前走的这个过程,他们的下一步到达的地方一定是递减的,不可以这一步到达的地方是之前已经可以到达的地方,这样可能会进入一个无效的查找过程,所以可以直接剪枝
然后我们也可以知道\(a_i<=i\),所以,最后到达\(0\)的一定是\(now\),因为只有\(a_i=i\)的时候才是可以到达\(0\)的,这是我们可以走的最远的路,要是还去休息,那不就是往后走了吗,所以只能是\(now\)走到\(0\),所以判断的时候注意一下
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn=1e6+10;
int dis[maxn];
int pre[maxn];
int n;
int a[maxn],b[maxn];
int bfs()
{
queue<pair<int,int>>q;
dis[n]=0;
q.push({n,n});
int dep=n;
while (!q.empty())
{
int now=q.front().first;
int u=q.front().second;
q.pop();
if (now==0) return dis[now];
for (int i=a[u];i>=1;i--)
{
int tnow=u-i;
if (tnow>=dep) break;
int tu=tnow+b[tnow];
if (dis[tnow]>dis[now]+1)
{
dis[tnow]=dis[now]+1;
q.push({tnow,tu});
pre[tnow]=now;
}
}
dep=min(dep,u-a[u]);
}
return -1;
}
int main ()
{
cin>>n;
for (int i=1;i<=n;i++)
{
cin>>a[i];
dis[i]=1e9+10;
}
dis[0]=1e9+10;
for (int i=1;i<=n;i++)
{
cin>>b[i];
}
int ans=bfs();
cout<<ans<<'\n';
if (ans!=-1)
{
vector<int>p;
for (int j=n,i=1;i<=ans;j=pre[j])
{
p.push_back(pre[j]);
i++;
}
for (int i=ans-1;i>=0;i--)
{
cout<<p[i]<<" ";
}
cout<<'\n';
}
system ("pause");
return 0;
}

浙公网安备 33010602011771号