Codeforces Round #605 (Div. 3)E

题意:

给n长度的数组,a1,a2,a3,a4,a5…an,他可以实现跳跃从 ai 跳到a(i-ai)或者a(i+ai)这其中i-ai>=1  i+ai<=n

问如果他跳跃到的地方与他ai值的奇偶不同,就停止跳跃,比如 1 2 3,a1->a(1+1)=2就停止了,a2->a(2+2or2-2)都不符合所以没有跳,输出-1

其中跳不了和跳不到与ai奇偶不同的地方就输出-1

问每个位置需要最少跳几次。

思路

搜索,怎么搜呢,先找到一步就能跳到的点,ai%2!=aj%2同时i+ai==j或者i-ai==j这种。

然后这里就是看别人大佬的思路了,思路贼清晰,建一个ai%2==aj%2 && i+ai==j或者i-ai==j

前者建边是ai+i->i   后者是i-ai->i 的。为什么这样呢,这是从 一步就跳到的点 开始广搜。从最小步数往大步数搜。如果这个点之前没搜到过的点,就是bu+1,然后存进去

 

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define il inline
#define it register int
#define inf 0x3f3f3f3f
#define lowbit(x) (x)&(-x)
#define pii pair<int,int>
#define mak(n,m) make_pair(n,m)
#define mem(a,b) memset(a,b,sizeof(a))
#define mod 998244353
const int maxn=2e5+10;
struct node{
    int v,next;
}a[maxn<<1];
int cnt,head[maxn],n,m,t,aa[maxn];
il void add(int u,int v){
    a[cnt].v=v;a[cnt].next=head[u];
    head[u]=cnt++;
}
int bu[maxn];
queue<int>q;
int main(){
    mem(head,-1);mem(bu,-1);
    scanf("%d",&n);
    for(it i=1;i<=n;i++){
        scanf("%d",&aa[i]);
    }
    for(it i=1;i<=n;i++){
        if(i-aa[i]>0 && aa[i]%2==aa[i-aa[i]]%2){
            add(i-aa[i],i);
        }
        if(i+aa[i]<=n && aa[i]%2==aa[i+aa[i]]%2){
            add(i+aa[i],i);
        }
    }
    for(it i=1;i<=n;i++){
        if(i-aa[i]>0 && aa[i]%2!=aa[i-aa[i]]%2 || i+aa[i]<=n && aa[i]%2!=aa[i+aa[i]]%2){
            bu[i]=1;q.push(i);
        }
    }
    while(!q.empty()){
        int u=q.front();q.pop();
        for(it i=head[u];~i;i=a[i].next){
            int v=a[i].v;
            if(bu[v]==-1 || bu[v]>bu[u]+1){
                bu[v]=bu[u]+1;q.push(v);
            }
        }
    }
    for(it i=1;i<=n;i++){
        printf(i==n?"%d\n":"%d ",bu[i]);
    }
    return 0;
}

 

 

感觉思路好清晰,把它直接转换为图来搜,这种想法受教了

posted @ 2020-03-17 22:57  ouluy  阅读(148)  评论(0编辑  收藏  举报