题意:青蛙掉进井了,它要跳出坑。现在青蛙在深度为n的坑中。它在深度i的坑,最多能向上跳跃 a i a_i ai的高度;当青蛙跳到新的位置i,由于摩檫力和体力消化等因素,它会往后滑 b i b_i bi。现在青蛙从位置n,要跳到地面(位置0),问最小需要跳多少次,并输出路径。如果跳不出(跳不出也太难了233),输出(-1)。
思路:广搜,每次入队的点都是下滑前的位置。为保证线性复杂度,维护最近的跳跃点lst。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 300010;
int n;
int a[maxn], b[maxn], c[maxn];
int pre[maxn], vis[maxn];
vector<int> ans;
void cal_ans(int k) {
// printf("k :%d\n", k);
while (pre[k] != -1) {
ans.push_back(k);
k = pre[k];
}
}
void print_ans() {
int sz = ans.size();
printf("%d\n", sz);
for (int i = sz - 1; i > 0; --i) {
printf("%d ", ans[i]);
}
printf("%d\n", ans[0]);
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
}
for (int i = 1; i <= n; ++i) {
scanf("%d", &b[i]);
}
for (int i = 1; i <= n; ++i) {
c[i+b[i]] = i;
}
int step = 0, mn = n;
queue<int> q;
ans.clear();
memset(vis, 0, sizeof(vis));
memset(pre, -1, sizeof(pre));
q.push(n);
vis[n] = 1;
int lst = n;
while (!q.empty() && ans.empty()) {
int sz = q.size();
while (sz-- && ans.empty()) {
int cur = q.front();
q.pop();
int node = cur;
cur = cur + b[cur];
int val = a[cur];
for (int k = min(lst, cur); k >= cur - val; --k) {
if (0 == k) {
ans.push_back(0);
cal_ans(node);
break;
}
if (vis[k]) continue;
pre[k] = node;
vis[k] = 1;
q.push(k);
}
lst = min(lst, cur - val);
}
}
if (ans.empty()) {
printf("-1\n");
} else {
print_ans();
}
}
官方题解是提供了线段树做法,复杂度nlogn,贴下网友ssllyg大佬的代码。这种线段树思路我没想到,学习下。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define N 300300
using namespace std;
int n,now,v[N],a[N],b[N],lst[N];
struct Tree
{
#define ls x*2
#define rs x*2+1
int s[N<<2],lazy[N<<2];
void push_up(int x)
{
if(v[s[ls]]<v[s[rs]])s[x]=s[ls];//因为要存路径,所以更改存的方式
else s[x]=s[rs];
return;
}
void get(int x,int y)
{
if(v[s[x]]>v[y])s[x]=y;
if(v[lazy[x]]>v[y])lazy[x]=y;
return;
}
void build(int x,int l,int r)
{
s[x]=lazy[x]=n+2;
if(l==r)return;
int mid=l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
return;
}
void push_down(int x)
{
if(lazy[x]!=n+2){
get(ls,lazy[x]);
get(rs,lazy[x]);
lazy[x]=n+2;
}
return;
}
void add(int x,int L,int R,int l,int r,int y)
{
if(L==l&&R==r){
get(x,y);
return;
}
push_down(x);
int mid=L+R>>1;
if(r<=mid)add(ls,L,mid,l,r,y);
else if(l>mid)add(rs,mid+1,R,l,r,y);
else add(ls,L,mid,l,mid,y),add(rs,mid+1,R,mid+1,r,y);
push_up(x);
}
int ask(int x,int l,int r,int y)
{
if(l==r)return s[x];
push_down(x);
int mid=l+r>>1;
if(y<=mid)return ask(ls,l,mid,y);
else return ask(rs,mid+1,r,y);
}
}T;
void dfs(int x)
{
if(x==n)return;
dfs(lst[x]);
printf("%d ",x-1);
}
int main()
{
scanf("%d",&n);
n++;
for(int i=2;i<=n;++i)
scanf("%d",&a[i]);
for(int i=2;i<=n;++i)
scanf("%d",&b[i]);
T.build(1,1,n);
v[n+2]=1e9;
v[n+1]=0;
T.add(1,1,n,n,n,n+1);
for(int i=n;i>1;--i){
lst[i]=T.ask(1,1,n,i);
v[i]=v[lst[i]]+1;
now=i+b[i];//往后bi步
T.add(1,1,n,now-a[now],now,i);
}
lst[1]=T.ask(1,1,n,1);
v[1]=v[lst[1]]+1;
if(lst[1]==n+2){
puts("-1");
return 0;
}
printf("%d\n",v[1]-1);
now=1;
dfs(1);
return 0;
}
(PS,今天漫神生日,祝漫神生日快乐,虽然漫神不看我的博客233)